(*
MP3 codec library

This file is a part of Audio Components Suite.
All rights reserved. See the license file for more details.

Copyright (c) 2019  Sergey Bodrov, serbod@gmail.com

Original version written by Krister Lagerström(krister@kmlager.com)
Website: https://sites.google.com/a/kmlager.com/www/projects

ported from PDMP3 Public domain mp3 decoder

Usage example:

procedure Decode(fsIn, fsOut: TStream);
var
  id: TPdmp3Handle;
  res, InSize, OutSize: Integer;
  InBuf, OutBuf: TByteArray;
begin
  pdmp3_open_feed(id);
  res := PDMP3_NEED_MORE;
  while (res = PDMP3_OK) or (res = PDMP3_NEED_MORE) do
  begin
    // transcode
    inSize := fsIn.Read(InBuf, 2048);
    res := pdmp3_decode(id, InBuf, inSize, OutBuf, SizeOf(OutBuf), OutSize);
    if (res = PDMP3_OK) or (res = PDMP3_NEED_MORE) then
    begin
      fsOut.Write(OutBuf, OutSize);
    end;
  end;
end;

*)
unit mp3;

interface

{$mode DELPHI}

uses
  SysUtils;

{ pre-calculate table, take 65656 bytes, but greatly offload CPU }
{$define POW34_TABLE}

{ pre-calculate table, bit more precise }
{$define IMDCT_TABLE}

{ use predefined tables, take 1224 bytes, but greatly offload CPU }
{$define IMDCT_NTABLES}

{ pre-calculate table, take 2048 bytes, but greatly offload CPU }
{$define GGAIN_TABLE}

{ print debug info to STDOUT }
{//$define ACS_DEBUG}

type
  { Types used in the frame header }

  { Layer number }
  TMpeg1Layer = (mpeg1LayerReserved = 0,
                 mpeg1Layer3        = 1,
                 mpeg1Layer2        = 2,
                 mpeg1Layer1        = 3);

  { Modes }
  TMpeg1Mode = (mpeg1ModeStereo = 0,
                mpeg1ModeJointStereo,
                mpeg1ModeDualChannel,
                mpeg1ModeSingleChannel);


  { MPEG1 Layer 1-3 frame header (32 bits) }
  TMpeg1Header = bitpacked record
    Sync: 0..2047;               // 11 bits  MP3 Sync Word
    Version: 0..1;               // 1 bit    Version, 0 = verion 2, 1 = verion 1
    Id: 0..1;                    // 1 bit    Version, 1 = MPEG
    Layer: 0..3;                 // 2 bits   0 = reserved, 1 = 3, 2 = 2, 3 = 1
    ProtectionBit: 0..1;         // 1 bit    Error protection, 1 = disabled
    BitrateIndex: 0..15;         // 4 bits
    SamplingFrequency: 0..3;     // 2 bits   Sampling frequency index, 0 = 44.1, 1 = 48, 2 = 32, 3 = unknown
    PaddingBit: 0..1;            // 1 bit
    PrivateBit: 0..1;            // 1 bit
    Mode: 0..3;                  // 2 bits   0 = Stereo, 1 = JointStereo, 2 = DualChannel, 3 = SingleChannel
    ModeExtension: 0..3;         // 2 bits   for joint stereo
    Copyright: 0..1;             // 1 bit    False = not copyrighted
    Original: 0..1;              // 1 bit    False = copy, True = original
    Emphasis: 0..3;              // 2 bits   0 = none, 1 = 50/15 ms, 2 = reserved, 3 = CCIT J.17
  end;

  (*
  { MPEG1 Layer 3 Block (22 bit) }
  TMpeg1Block = bitpacked record
    BlockType: 0..3;                  // 2 bits
    MixedBlockFlag: Boolean;          // 1 bit
    TableSelect: array[0..1] of 0..31;  // 2 regions (5 bits)
    SubblockGain: array[0..2] of 0..7;  // 3 windows (3 bits)
  end;

  { MPEG1 Layer 3 Region (22 bit) }
  TMpeg1Region = bitpacked record
    TableSelect: array[0..2] of 0..31;  // 3 regions (5 bits)
    Region0Count: 0..15;              // 4 bits
    Region1Count: 0..7;               // 3 bits
  end;

  { MPEG1 Layer 3 Granule }
  TMpeg1Granule = bitpacked record
    Part2_3_length: 0..4095;    // 12 bits
    Big_values: 0..511;         // 9 bits
    GlobalGain: Byte;           // 8 bits
    ScalefacCompress: 0..15;    // 4 bits
    WinSwitchFlag: Boolean;     // 1 bit    0=Region, 1=Block
    //...
    Block: TMpeg1Block;
    Region: TMpeg1Region;
    //...
    ScalefacScale: Boolean;     // 1 bit
    Count1TableSelect: Boolean; // 1 bit
  end;

  { MPEG1 Layer 3 Side Information (mono, 17 bits) }
  TMpeg1SideInfoMono = bitpacked record
    MainDataBegin: Byte;         // 8 bits
    PrivateBits: 0..1;           // 1 bit in mono
    //Scfsi: 0..15;                // 4 bit
    Granule: array of TMpeg1Granule;
  end;

  { MPEG1 Layer 3 Side Information (32 bits) }
  TMpeg1SideInfoChannel = bitpacked record
    MainDataBegin: 0..255;         // 8 bits
    PrivateBits: 0..3;             // 1 in mono, 2 in stereo
    Scfsi: Byte;                   // 8 bit
    Granule: array of TMpeg1Granule;
  end;
  *)

  { for compatibility, remove later }
  TMpeg1SideInfo = record
    MainDataBegin: 0..511;           // 9 bits    (reservoir size)
    PrivateBits: Byte;              // 3 bits in mono,5 in stereo   (padding)
    Scfsi: array[0..1, 0..3] of Byte;    // 1 bit
    Part2_3_length: array [0..1, 0..1] of Word;    // 12 bits
    BigValues: array [0..1, 0..1] of Word;         // 9 bits
    GlobalGain: array [0..1, 0..1] of Byte;        // 8 bits
    ScalefacCompress: array [0..1, 0..1] of Byte;  // 4 bits
    WinSwitchFlag: array [0..1, 0..1] of Byte;     // 1 bit
    { if(win_switch_flag[][]) } //use a union dammit
    BlockType: array [0..1, 0..1] of Byte;         // 2 bits
    MixedBlockFlag: array [0..1, 0..1] of Byte;    // 1 bit
    TableSelect: array [0..1, 0..1, 0..2] of Byte;    // 5 bits
    SubblockGain: array [0..1, 0..1, 0..2] of Byte;   // 3 bits
    { else }
    { table_select[][][] }
    Region0Count: array [0..1, 0..1] of Byte;      // 4 bits
    Region1Count: array [0..1, 0..1] of Byte;      // 3 bits
    { end }
    Preflag: array [0..1, 0..1] of Byte;           // 1 bit
    ScalefacScale: array [0..1, 0..1] of Byte;     // 1 bit
    Count1TableSelect: array [0..1, 0..1] of Byte; // 1 bit
    Count1: array[0..1, 0..1] of Integer;          // Not in file,calc. by huff.dec.!
  end;

  { MPEG1 Layer 3 Main Data }
  TMpeg1MainData = record
    ScalefacL: array[0..1, 0..1, 0..21] of Byte;    // 0-4 bits
    ScalefacS: array[0..1, 0..1, 0..12, 0..2] of Byte; // 0-4 bits
    ls: array[0..1, 0..1, 0..575] of Real;          // Huffman coded freq. lines
  end;

  THuffTables = record
    //Hufftable: PWord;
    HuffTable: Word;     // index in GHuffmanTable
    TreeLen: Word;
    LinBits: Byte;
  end;


  { Scale factor band indices,for long and short windows }
  TSfBandIndices = record
    l: array[0..22] of Word;
    s: array[0..13] of Word;
  end;

{ define a subset of a libmpg123 compatible streaming API }
const
  PDMP3_OK          = 0;
  PDMP3_ERR         = -1;
  PDMP3_NEED_MORE   = -10;
  PDMP3_NEW_FORMAT  = -11;
  PDMP3_NO_SPACE    = 7;

  PDMP3_ENC_SIGNED_16  = ($80 or $40 or $10);

  INBUF_SIZE        = (4*4096);

type
  TLongWordArr576 = array[0..575] of LongWord;
  TRealArr18 = array[0..17] of Real;
  TRealArr36 = array[0..35] of Real;

  TPdmp3Handle = record
    Processed: Integer;
    IStart, IEnd, OStart: Integer;
    _in: array[0..INBUF_SIZE-1] of Byte;
    _out: array[0..1] of TLongWordArr576;
    GFrameHeader: TMpeg1Header;
    GSideInfo: TMpeg1SideInfo;  // < 100 words
    GMainData: TMpeg1MainData;

    HSynthInit: Word;
    HSynthStore: array[0..1, 0..31] of TRealArr18;

    SynthInit: Word;
    { Bit reservoir for main data }
    GMainDataVec: array[0..2047] of Byte; // Large static data
    //GMainDataPtr: PByte;                 // Pointer into the reservoir
    GMainDataPos: Integer;                 // Position in GMainDataVec
    GMainDataIdx: Byte;                  // Index into the current byte (0-7)
    GMainDataTop: Word;                  // Number of bytes in reservoir(0-1024)
    { Bit reservoir for side info }
    SideInfoVec: array[0..32+4-1] of Byte;
    SideInfoPtr: PByte;                  // Pointer into the reservoir
    SideInfoIdx: Byte;                   // Index into the current byte(0-7)
    { synth data }
    v_vec: array[0..1, 0..1023] of Real;

    NewHeader: Integer;
  end;

{function pdmp3_new(const decoder: string; out error: Integer): TPdmp3Handle;
procedure pdmp3_delete(var id: TPdmp3Handle);}
function pdmp3_open_feed(var id: TPdmp3Handle): Integer;
function pdmp3_feed(var id: TPdmp3Handle; const AIn; ASize: Integer): Integer;
function pdmp3_read(var id: TPdmp3Handle; var outmemory; outsize: Integer; out done: Integer): Integer;
function pdmp3_decode(var id: TPdmp3Handle; const AIn; AInSize: Integer;
  var AOut; AOutSize: Integer; out ADone: Integer): Integer;
function pdmp3_getformat(var id: TPdmp3Handle; out rate, channels, encoding: Integer): Integer;
{ end of the subset of a libmpg123 compatible streaming API }

{ Calculate header audio data size }
function GetFrameSize(const id: TPdmp3Handle): Integer; inline;
{ Return number of samples per single frame }
function GetSamplesPerFrame(const id: TPdmp3Handle): Integer;

{procedure pdmp3(const mp3s: string);   }

implementation

uses Math;

{$ifndef PDMP3_HEADER_ONLY}
  {$define SIM_UNIX}
{$endif}

type
  TMp3Statistic = record
    FrameNum: Integer;
  end;

{$ifdef POW34_TABLE}
var powtab34: array[0..8206] of Real;
{$endif}

{$ifdef IMDCT_TABLE}
var GImdctWin: array[0..3, 0..35] of Real;
{$endif}

{$ifdef GGAIN_TABLE}
var GlobalGainTable: array[Byte] of Real;
{$endif}

{ synth table }
var GSynthNWin: array[0..63, 0..31] of Real;

var
  Mp3Stats: TMp3Statistic;

const
//#define TRUE       1
//#define FALSE      0
  C_SYNC             = $fff00000;
  C_EOF              = -1;
  C_PI               = 3.14159265358979323846;
  C_INV_SQRT_2       = 0.70710678118654752440;
  Hz                 = 1;
  kHz                = 1000 * Hz;
  bit_s              = 1;
  kbit_s             = 1000 * bit_s;
  FRAG_SIZE_LN2     = $0011; // 2^17=128kb
  FRAG_NUMS         = $0004;

  GHuffmanTable: array [0..2803] of Word = (
  //g_huffman_table_1[7] = {
    $0201, $0000, $0201, $0010, $0201, $0001, $0011,
  //},g_huffman_table_2[17] = {
    $0201, $0000, $0401, $0201, $0010, $0001, $0201, $0011, $0401, $0201, $0020,
    $0021, $0201, $0012, $0201, $0002, $0022,
  //},g_huffman_table_3[17] = {
    $0401, $0201, $0000, $0001, $0201, $0011, $0201, $0010, $0401, $0201, $0020,
    $0021, $0201, $0012, $0201, $0002, $0022,
  //},g_huffman_table_5[31] = {
    $0201, $0000, $0401, $0201, $0010, $0001, $0201, $0011, $0801, $0401, $0201,
    $0020, $0002, $0201, $0021, $0012, $0801, $0401, $0201, $0022, $0030, $0201,
    $0003, $0013, $0201, $0031, $0201, $0032, $0201, $0023, $0033,
  //},g_huffman_table_6[31] = {
    $0601, $0401, $0201, $0000, $0010, $0011, $0601, $0201, $0001, $0201, $0020,
    $0021, $0601, $0201, $0012, $0201, $0002, $0022, $0401, $0201, $0031, $0013,
    $0401, $0201, $0030, $0032, $0201, $0023, $0201, $0003, $0033,
  //},g_huffman_table_7[71] = {
    $0201, $0000, $0401, $0201, $0010, $0001, $0801, $0201, $0011, $0401, $0201,
    $0020, $0002, $0021, $1201, $0601, $0201, $0012, $0201, $0022, $0030, $0401,
    $0201, $0031, $0013, $0401, $0201, $0003, $0032, $0201, $0023, $0004, $0a01,
    $0401, $0201, $0040, $0041, $0201, $0014, $0201, $0042, $0024, $0c01, $0601,
    $0401, $0201, $0033, $0043, $0050, $0401, $0201, $0034, $0005, $0051, $0601,
    $0201, $0015, $0201, $0052, $0025, $0401, $0201, $0044, $0035, $0401, $0201,
    $0053, $0054, $0201, $0045, $0055,
  //},g_huffman_table_8[71] = {
    $0601, $0201, $0000, $0201, $0010, $0001, $0201, $0011, $0401, $0201, $0021,
    $0012, $0e01, $0401, $0201, $0020, $0002, $0201, $0022, $0401, $0201, $0030,
    $0003, $0201, $0031, $0013, $0e01, $0801, $0401, $0201, $0032, $0023, $0201,
    $0040, $0004, $0201, $0041, $0201, $0014, $0042, $0c01, $0601, $0201, $0024,
    $0201, $0033, $0050, $0401, $0201, $0043, $0034, $0051, $0601, $0201, $0015,
    $0201, $0005, $0052, $0601, $0201, $0025, $0201, $0044, $0035, $0201, $0053,
    $0201, $0045, $0201, $0054, $0055,
  //},g_huffman_table_9[71] = {
    $0801, $0401, $0201, $0000, $0010, $0201, $0001, $0011, $0a01, $0401, $0201,
    $0020, $0021, $0201, $0012, $0201, $0002, $0022, $0c01, $0601, $0401, $0201,
    $0030, $0003, $0031, $0201, $0013, $0201, $0032, $0023, $0c01, $0401, $0201,
    $0041, $0014, $0401, $0201, $0040, $0033, $0201, $0042, $0024, $0a01, $0601,
    $0401, $0201, $0004, $0050, $0043, $0201, $0034, $0051, $0801, $0401, $0201,
    $0015, $0052, $0201, $0025, $0044, $0601, $0401, $0201, $0005, $0054, $0053,
    $0201, $0035, $0201, $0045, $0055,
  //},g_huffman_table_10[127] = {
    $0201, $0000, $0401, $0201, $0010, $0001, $0a01, $0201, $0011, $0401, $0201,
    $0020, $0002, $0201, $0021, $0012, $1c01, $0801, $0401, $0201, $0022, $0030,
    $0201, $0031, $0013, $0801, $0401, $0201, $0003, $0032, $0201, $0023, $0040,
    $0401, $0201, $0041, $0014, $0401, $0201, $0004, $0033, $0201, $0042, $0024,
    $1c01, $0a01, $0601, $0401, $0201, $0050, $0005, $0060, $0201, $0061, $0016,
    $0c01, $0601, $0401, $0201, $0043, $0034, $0051, $0201, $0015, $0201, $0052,
    $0025, $0401, $0201, $0026, $0036, $0071, $1401, $0801, $0201, $0017, $0401,
    $0201, $0044, $0053, $0006, $0601, $0401, $0201, $0035, $0045, $0062, $0201,
    $0070, $0201, $0007, $0064, $0e01, $0401, $0201, $0072, $0027, $0601, $0201,
    $0063, $0201, $0054, $0055, $0201, $0046, $0073, $0801, $0401, $0201, $0037,
    $0065, $0201, $0056, $0074, $0601, $0201, $0047, $0201, $0066, $0075, $0401,
    $0201, $0057, $0076, $0201, $0067, $0077,
  //},g_huffman_table_11[127] = {
    $0601, $0201, $0000, $0201, $0010, $0001, $0801, $0201, $0011, $0401, $0201,
    $0020, $0002, $0012, $1801, $0801, $0201, $0021, $0201, $0022, $0201, $0030,
    $0003, $0401, $0201, $0031, $0013, $0401, $0201, $0032, $0023, $0401, $0201,
    $0040, $0004, $0201, $0041, $0014, $1e01, $1001, $0a01, $0401, $0201, $0042,
    $0024, $0401, $0201, $0033, $0043, $0050, $0401, $0201, $0034, $0051, $0061,
    $0601, $0201, $0016, $0201, $0006, $0026, $0201, $0062, $0201, $0015, $0201,
    $0005, $0052, $1001, $0a01, $0601, $0401, $0201, $0025, $0044, $0060, $0201,
    $0063, $0036, $0401, $0201, $0070, $0017, $0071, $1001, $0601, $0401, $0201,
    $0007, $0064, $0072, $0201, $0027, $0401, $0201, $0053, $0035, $0201, $0054,
    $0045, $0a01, $0401, $0201, $0046, $0073, $0201, $0037, $0201, $0065, $0056,
    $0a01, $0601, $0401, $0201, $0055, $0057, $0074, $0201, $0047, $0066, $0401,
    $0201, $0075, $0076, $0201, $0067, $0077,
  //},g_huffman_table_12[127] = {
    $0c01, $0401, $0201, $0010, $0001, $0201, $0011, $0201, $0000, $0201, $0020,
    $0002, $1001, $0401, $0201, $0021, $0012, $0401, $0201, $0022, $0031, $0201,
    $0013, $0201, $0030, $0201, $0003, $0040, $1a01, $0801, $0401, $0201, $0032,
    $0023, $0201, $0041, $0033, $0a01, $0401, $0201, $0014, $0042, $0201, $0024,
    $0201, $0004, $0050, $0401, $0201, $0043, $0034, $0201, $0051, $0015, $1c01,
    $0e01, $0801, $0401, $0201, $0052, $0025, $0201, $0053, $0035, $0401, $0201,
    $0060, $0016, $0061, $0401, $0201, $0062, $0026, $0601, $0401, $0201, $0005,
    $0006, $0044, $0201, $0054, $0045, $1201, $0a01, $0401, $0201, $0063, $0036,
    $0401, $0201, $0070, $0007, $0071, $0401, $0201, $0017, $0064, $0201, $0046,
    $0072, $0a01, $0601, $0201, $0027, $0201, $0055, $0073, $0201, $0037, $0056,
    $0801, $0401, $0201, $0065, $0074, $0201, $0047, $0066, $0401, $0201, $0075,
    $0057, $0201, $0076, $0201, $0067, $0077,
  //},g_huffman_table_13[511] = {
    $0201, $0000, $0601, $0201, $0010, $0201, $0001, $0011, $1c01, $0801, $0401,
    $0201, $0020, $0002, $0201, $0021, $0012, $0801, $0401, $0201, $0022, $0030,
    $0201, $0003, $0031, $0601, $0201, $0013, $0201, $0032, $0023, $0401, $0201,
    $0040, $0004, $0041, $4601, $1c01, $0e01, $0601, $0201, $0014, $0201, $0033,
    $0042, $0401, $0201, $0024, $0050, $0201, $0043, $0034, $0401, $0201, $0051,
    $0015, $0401, $0201, $0005, $0052, $0201, $0025, $0201, $0044, $0053, $0e01,
    $0801, $0401, $0201, $0060, $0006, $0201, $0061, $0016, $0401, $0201, $0080,
    $0008, $0081, $1001, $0801, $0401, $0201, $0035, $0062, $0201, $0026, $0054,
    $0401, $0201, $0045, $0063, $0201, $0036, $0070, $0601, $0401, $0201, $0007,
    $0055, $0071, $0201, $0017, $0201, $0027, $0037, $4801, $1801, $0c01, $0401,
    $0201, $0018, $0082, $0201, $0028, $0401, $0201, $0064, $0046, $0072, $0801,
    $0401, $0201, $0084, $0048, $0201, $0090, $0009, $0201, $0091, $0019, $1801,
    $0e01, $0801, $0401, $0201, $0073, $0065, $0201, $0056, $0074, $0401, $0201,
    $0047, $0066, $0083, $0601, $0201, $0038, $0201, $0075, $0057, $0201, $0092,
    $0029, $0e01, $0801, $0401, $0201, $0067, $0085, $0201, $0058, $0039, $0201,
    $0093, $0201, $0049, $0086, $0601, $0201, $00a0, $0201, $0068, $000a, $0201,
    $00a1, $001a, $4401, $1801, $0c01, $0401, $0201, $00a2, $002a, $0401, $0201,
    $0095, $0059, $0201, $00a3, $003a, $0801, $0401, $0201, $004a, $0096, $0201,
    $00b0, $000b, $0201, $00b1, $001b, $1401, $0801, $0201, $00b2, $0401, $0201,
    $0076, $0077, $0094, $0601, $0401, $0201, $0087, $0078, $00a4, $0401, $0201,
    $0069, $00a5, $002b, $0c01, $0601, $0401, $0201, $005a, $0088, $00b3, $0201,
    $003b, $0201, $0079, $00a6, $0601, $0401, $0201, $006a, $00b4, $00c0, $0401,
    $0201, $000c, $0098, $00c1, $3c01, $1601, $0a01, $0601, $0201, $001c, $0201,
    $0089, $00b5, $0201, $005b, $00c2, $0401, $0201, $002c, $003c, $0401, $0201,
    $00b6, $006b, $0201, $00c4, $004c, $1001, $0801, $0401, $0201, $00a8, $008a,
    $0201, $00d0, $000d, $0201, $00d1, $0201, $004b, $0201, $0097, $00a7, $0c01,
    $0601, $0201, $00c3, $0201, $007a, $0099, $0401, $0201, $00c5, $005c, $00b7,
    $0401, $0201, $001d, $00d2, $0201, $002d, $0201, $007b, $00d3, $3401, $1c01,
    $0c01, $0401, $0201, $003d, $00c6, $0401, $0201, $006c, $00a9, $0201, $009a,
    $00d4, $0801, $0401, $0201, $00b8, $008b, $0201, $004d, $00c7, $0401, $0201,
    $007c, $00d5, $0201, $005d, $00e0, $0a01, $0401, $0201, $00e1, $001e, $0401,
    $0201, $000e, $002e, $00e2, $0801, $0401, $0201, $00e3, $006d, $0201, $008c,
    $00e4, $0401, $0201, $00e5, $00ba, $00f0, $2601, $1001, $0401, $0201, $00f1,
    $001f, $0601, $0401, $0201, $00aa, $009b, $00b9, $0201, $003e, $0201, $00d6,
    $00c8, $0c01, $0601, $0201, $004e, $0201, $00d7, $007d, $0201, $00ab, $0201,
    $005e, $00c9, $0601, $0201, $000f, $0201, $009c, $006e, $0201, $00f2, $002f,
    $2001, $1001, $0601, $0401, $0201, $00d8, $008d, $003f, $0601, $0201, $00f3,
    $0201, $00e6, $00ca, $0201, $00f4, $004f, $0801, $0401, $0201, $00bb, $00ac,
    $0201, $00e7, $00f5, $0401, $0201, $00d9, $009d, $0201, $005f, $00e8, $1e01,
    $0c01, $0601, $0201, $006f, $0201, $00f6, $00cb, $0401, $0201, $00bc, $00ad,
    $00da, $0801, $0201, $00f7, $0401, $0201, $007e, $007f, $008e, $0601, $0401,
    $0201, $009e, $00ae, $00cc, $0201, $00f8, $008f, $1201, $0801, $0401, $0201,
    $00db, $00bd, $0201, $00ea, $00f9, $0401, $0201, $009f, $00eb, $0201, $00be,
    $0201, $00cd, $00fa, $0e01, $0401, $0201, $00dd, $00ec, $0601, $0401, $0201,
    $00e9, $00af, $00dc, $0201, $00ce, $00fb, $0801, $0401, $0201, $00bf, $00de,
    $0201, $00cf, $00ee, $0401, $0201, $00df, $00ef, $0201, $00ff, $0201, $00ed,
    $0201, $00fd, $0201, $00fc, $00fe,
  //},g_huffman_table_15[511] = {
    $1001, $0601, $0201, $0000, $0201, $0010, $0001, $0201, $0011, $0401, $0201,
    $0020, $0002, $0201, $0021, $0012, $3201, $1001, $0601, $0201, $0022, $0201,
    $0030, $0031, $0601, $0201, $0013, $0201, $0003, $0040, $0201, $0032, $0023,
    $0e01, $0601, $0401, $0201, $0004, $0014, $0041, $0401, $0201, $0033, $0042,
    $0201, $0024, $0043, $0a01, $0601, $0201, $0034, $0201, $0050, $0005, $0201,
    $0051, $0015, $0401, $0201, $0052, $0025, $0401, $0201, $0044, $0053, $0061,
    $5a01, $2401, $1201, $0a01, $0601, $0201, $0035, $0201, $0060, $0006, $0201,
    $0016, $0062, $0401, $0201, $0026, $0054, $0201, $0045, $0063, $0a01, $0601,
    $0201, $0036, $0201, $0070, $0007, $0201, $0071, $0055, $0401, $0201, $0017,
    $0064, $0201, $0072, $0027, $1801, $1001, $0801, $0401, $0201, $0046, $0073,
    $0201, $0037, $0065, $0401, $0201, $0056, $0080, $0201, $0008, $0074, $0401,
    $0201, $0081, $0018, $0201, $0082, $0028, $1001, $0801, $0401, $0201, $0047,
    $0066, $0201, $0083, $0038, $0401, $0201, $0075, $0057, $0201, $0084, $0048,
    $0601, $0401, $0201, $0090, $0019, $0091, $0401, $0201, $0092, $0076, $0201,
    $0067, $0029, $5c01, $2401, $1201, $0a01, $0401, $0201, $0085, $0058, $0401,
    $0201, $0009, $0077, $0093, $0401, $0201, $0039, $0094, $0201, $0049, $0086,
    $0a01, $0601, $0201, $0068, $0201, $00a0, $000a, $0201, $00a1, $001a, $0401,
    $0201, $00a2, $002a, $0201, $0095, $0059, $1a01, $0e01, $0601, $0201, $00a3,
    $0201, $003a, $0087, $0401, $0201, $0078, $00a4, $0201, $004a, $0096, $0601,
    $0401, $0201, $0069, $00b0, $00b1, $0401, $0201, $001b, $00a5, $00b2, $0e01,
    $0801, $0401, $0201, $005a, $002b, $0201, $0088, $0097, $0201, $00b3, $0201,
    $0079, $003b, $0801, $0401, $0201, $006a, $00b4, $0201, $004b, $00c1, $0401,
    $0201, $0098, $0089, $0201, $001c, $00b5, $5001, $2201, $1001, $0601, $0401,
    $0201, $005b, $002c, $00c2, $0601, $0401, $0201, $000b, $00c0, $00a6, $0201,
    $00a7, $007a, $0a01, $0401, $0201, $00c3, $003c, $0401, $0201, $000c, $0099,
    $00b6, $0401, $0201, $006b, $00c4, $0201, $004c, $00a8, $1401, $0a01, $0401,
    $0201, $008a, $00c5, $0401, $0201, $00d0, $005c, $00d1, $0401, $0201, $00b7,
    $007b, $0201, $001d, $0201, $000d, $002d, $0c01, $0401, $0201, $00d2, $00d3,
    $0401, $0201, $003d, $00c6, $0201, $006c, $00a9, $0601, $0401, $0201, $009a,
    $00b8, $00d4, $0401, $0201, $008b, $004d, $0201, $00c7, $007c, $4401, $2201,
    $1201, $0a01, $0401, $0201, $00d5, $005d, $0401, $0201, $00e0, $000e, $00e1,
    $0401, $0201, $001e, $00e2, $0201, $00aa, $002e, $0801, $0401, $0201, $00b9,
    $009b, $0201, $00e3, $00d6, $0401, $0201, $006d, $003e, $0201, $00c8, $008c,
    $1001, $0801, $0401, $0201, $00e4, $004e, $0201, $00d7, $007d, $0401, $0201,
    $00e5, $00ba, $0201, $00ab, $005e, $0801, $0401, $0201, $00c9, $009c, $0201,
    $00f1, $001f, $0601, $0401, $0201, $00f0, $006e, $00f2, $0201, $002f, $00e6,
    $2601, $1201, $0801, $0401, $0201, $00d8, $00f3, $0201, $003f, $00f4, $0601,
    $0201, $004f, $0201, $008d, $00d9, $0201, $00bb, $00ca, $0801, $0401, $0201,
    $00ac, $00e7, $0201, $007e, $00f5, $0801, $0401, $0201, $009d, $005f, $0201,
    $00e8, $008e, $0201, $00f6, $00cb, $2201, $1201, $0a01, $0601, $0401, $0201,
    $000f, $00ae, $006f, $0201, $00bc, $00da, $0401, $0201, $00ad, $00f7, $0201,
    $007f, $00e9, $0801, $0401, $0201, $009e, $00cc, $0201, $00f8, $008f, $0401,
    $0201, $00db, $00bd, $0201, $00ea, $00f9, $1001, $0801, $0401, $0201, $009f,
    $00dc, $0201, $00cd, $00eb, $0401, $0201, $00be, $00fa, $0201, $00af, $00dd,
    $0e01, $0601, $0401, $0201, $00ec, $00ce, $00fb, $0401, $0201, $00bf, $00ed,
    $0201, $00de, $00fc, $0601, $0401, $0201, $00cf, $00fd, $00ee, $0401, $0201,
    $00df, $00fe, $0201, $00ef, $00ff,
  //},g_huffman_table_16[511] = {
    $0201, $0000, $0601, $0201, $0010, $0201, $0001, $0011, $2a01, $0801, $0401,
    $0201, $0020, $0002, $0201, $0021, $0012, $0a01, $0601, $0201, $0022, $0201,
    $0030, $0003, $0201, $0031, $0013, $0a01, $0401, $0201, $0032, $0023, $0401,
    $0201, $0040, $0004, $0041, $0601, $0201, $0014, $0201, $0033, $0042, $0401,
    $0201, $0024, $0050, $0201, $0043, $0034, $8a01, $2801, $1001, $0601, $0401,
    $0201, $0005, $0015, $0051, $0401, $0201, $0052, $0025, $0401, $0201, $0044,
    $0035, $0053, $0a01, $0601, $0401, $0201, $0060, $0006, $0061, $0201, $0016,
    $0062, $0801, $0401, $0201, $0026, $0054, $0201, $0045, $0063, $0401, $0201,
    $0036, $0070, $0071, $2801, $1201, $0801, $0201, $0017, $0201, $0007, $0201,
    $0055, $0064, $0401, $0201, $0072, $0027, $0401, $0201, $0046, $0065, $0073,
    $0a01, $0601, $0201, $0037, $0201, $0056, $0008, $0201, $0080, $0081, $0601,
    $0201, $0018, $0201, $0074, $0047, $0201, $0082, $0201, $0028, $0066, $1801,
    $0e01, $0801, $0401, $0201, $0083, $0038, $0201, $0075, $0084, $0401, $0201,
    $0048, $0090, $0091, $0601, $0201, $0019, $0201, $0009, $0076, $0201, $0092,
    $0029, $0e01, $0801, $0401, $0201, $0085, $0058, $0201, $0093, $0039, $0401,
    $0201, $00a0, $000a, $001a, $0801, $0201, $00a2, $0201, $0067, $0201, $0057,
    $0049, $0601, $0201, $0094, $0201, $0077, $0086, $0201, $00a1, $0201, $0068,
    $0095, $dc01, $7e01, $3201, $1a01, $0c01, $0601, $0201, $002a, $0201, $0059,
    $003a, $0201, $00a3, $0201, $0087, $0078, $0801, $0401, $0201, $00a4, $004a,
    $0201, $0096, $0069, $0401, $0201, $00b0, $000b, $00b1, $0a01, $0401, $0201,
    $001b, $00b2, $0201, $002b, $0201, $00a5, $005a, $0601, $0201, $00b3, $0201,
    $00a6, $006a, $0401, $0201, $00b4, $004b, $0201, $000c, $00c1, $1e01, $0e01,
    $0601, $0401, $0201, $00b5, $00c2, $002c, $0401, $0201, $00a7, $00c3, $0201,
    $006b, $00c4, $0801, $0201, $001d, $0401, $0201, $0088, $0097, $003b, $0401,
    $0201, $00d1, $00d2, $0201, $002d, $00d3, $1201, $0601, $0401, $0201, $001e,
    $002e, $00e2, $0601, $0401, $0201, $0079, $0098, $00c0, $0201, $001c, $0201,
    $0089, $005b, $0e01, $0601, $0201, $003c, $0201, $007a, $00b6, $0401, $0201,
    $004c, $0099, $0201, $00a8, $008a, $0601, $0201, $000d, $0201, $00c5, $005c,
    $0401, $0201, $003d, $00c6, $0201, $006c, $009a, $5801, $5601, $2401, $1001,
    $0801, $0401, $0201, $008b, $004d, $0201, $00c7, $007c, $0401, $0201, $00d5,
    $005d, $0201, $00e0, $000e, $0801, $0201, $00e3, $0401, $0201, $00d0, $00b7,
    $007b, $0601, $0401, $0201, $00a9, $00b8, $00d4, $0201, $00e1, $0201, $00aa,
    $00b9, $1801, $0a01, $0601, $0401, $0201, $009b, $00d6, $006d, $0201, $003e,
    $00c8, $0601, $0401, $0201, $008c, $00e4, $004e, $0401, $0201, $00d7, $00e5,
    $0201, $00ba, $00ab, $0c01, $0401, $0201, $009c, $00e6, $0401, $0201, $006e,
    $00d8, $0201, $008d, $00bb, $0801, $0401, $0201, $00e7, $009d, $0201, $00e8,
    $008e, $0401, $0201, $00cb, $00bc, $009e, $00f1, $0201, $001f, $0201, $000f,
    $002f, $4201, $3801, $0201, $00f2, $3401, $3201, $1401, $0801, $0201, $00bd,
    $0201, $005e, $0201, $007d, $00c9, $0601, $0201, $00ca, $0201, $00ac, $007e,
    $0401, $0201, $00da, $00ad, $00cc, $0a01, $0601, $0201, $00ae, $0201, $00db,
    $00dc, $0201, $00cd, $00be, $0601, $0401, $0201, $00eb, $00ed, $00ee, $0601,
    $0401, $0201, $00d9, $00ea, $00e9, $0201, $00de, $0401, $0201, $00dd, $00ec,
    $00ce, $003f, $00f0, $0401, $0201, $00f3, $00f4, $0201, $004f, $0201, $00f5,
    $005f, $0a01, $0201, $00ff, $0401, $0201, $00f6, $006f, $0201, $00f7, $007f,
    $0c01, $0601, $0201, $008f, $0201, $00f8, $00f9, $0401, $0201, $009f, $00fa,
    $00af, $0801, $0401, $0201, $00fb, $00bf, $0201, $00fc, $00cf, $0401, $0201,
    $00fd, $00df, $0201, $00fe, $00ef,
  //},g_huffman_table_24[512] = {
    $3c01, $0801, $0401, $0201, $0000, $0010, $0201, $0001, $0011, $0e01, $0601,
    $0401, $0201, $0020, $0002, $0021, $0201, $0012, $0201, $0022, $0201, $0030,
    $0003, $0e01, $0401, $0201, $0031, $0013, $0401, $0201, $0032, $0023, $0401,
    $0201, $0040, $0004, $0041, $0801, $0401, $0201, $0014, $0033, $0201, $0042,
    $0024, $0601, $0401, $0201, $0043, $0034, $0051, $0601, $0401, $0201, $0050,
    $0005, $0015, $0201, $0052, $0025, $fa01, $6201, $2201, $1201, $0a01, $0401,
    $0201, $0044, $0053, $0201, $0035, $0201, $0060, $0006, $0401, $0201, $0061,
    $0016, $0201, $0062, $0026, $0801, $0401, $0201, $0054, $0045, $0201, $0063,
    $0036, $0401, $0201, $0071, $0055, $0201, $0064, $0046, $2001, $0e01, $0601,
    $0201, $0072, $0201, $0027, $0037, $0201, $0073, $0401, $0201, $0070, $0007,
    $0017, $0a01, $0401, $0201, $0065, $0056, $0401, $0201, $0080, $0008, $0081,
    $0401, $0201, $0074, $0047, $0201, $0018, $0082, $1001, $0801, $0401, $0201,
    $0028, $0066, $0201, $0083, $0038, $0401, $0201, $0075, $0057, $0201, $0084,
    $0048, $0801, $0401, $0201, $0091, $0019, $0201, $0092, $0076, $0401, $0201,
    $0067, $0029, $0201, $0085, $0058, $5c01, $2201, $1001, $0801, $0401, $0201,
    $0093, $0039, $0201, $0094, $0049, $0401, $0201, $0077, $0086, $0201, $0068,
    $00a1, $0801, $0401, $0201, $00a2, $002a, $0201, $0095, $0059, $0401, $0201,
    $00a3, $003a, $0201, $0087, $0201, $0078, $004a, $1601, $0c01, $0401, $0201,
    $00a4, $0096, $0401, $0201, $0069, $00b1, $0201, $001b, $00a5, $0601, $0201,
    $00b2, $0201, $005a, $002b, $0201, $0088, $00b3, $1001, $0a01, $0601, $0201,
    $0090, $0201, $0009, $00a0, $0201, $0097, $0079, $0401, $0201, $00a6, $006a,
    $00b4, $0c01, $0601, $0201, $001a, $0201, $000a, $00b0, $0201, $003b, $0201,
    $000b, $00c0, $0401, $0201, $004b, $00c1, $0201, $0098, $0089, $4301, $2201,
    $1001, $0801, $0401, $0201, $001c, $00b5, $0201, $005b, $00c2, $0401, $0201,
    $002c, $00a7, $0201, $007a, $00c3, $0a01, $0601, $0201, $003c, $0201, $000c,
    $00d0, $0201, $00b6, $006b, $0401, $0201, $00c4, $004c, $0201, $0099, $00a8,
    $1001, $0801, $0401, $0201, $008a, $00c5, $0201, $005c, $00d1, $0401, $0201,
    $00b7, $007b, $0201, $001d, $00d2, $0901, $0401, $0201, $002d, $00d3, $0201,
    $003d, $00c6, $55fa, $0401, $0201, $006c, $00a9, $0201, $009a, $00d4, $2001,
    $1001, $0801, $0401, $0201, $00b8, $008b, $0201, $004d, $00c7, $0401, $0201,
    $007c, $00d5, $0201, $005d, $00e1, $0801, $0401, $0201, $001e, $00e2, $0201,
    $00aa, $00b9, $0401, $0201, $009b, $00e3, $0201, $00d6, $006d, $1401, $0a01,
    $0601, $0201, $003e, $0201, $002e, $004e, $0201, $00c8, $008c, $0401, $0201,
    $00e4, $00d7, $0401, $0201, $007d, $00ab, $00e5, $0a01, $0401, $0201, $00ba,
    $005e, $0201, $00c9, $0201, $009c, $006e, $0801, $0201, $00e6, $0201, $000d,
    $0201, $00e0, $000e, $0401, $0201, $00d8, $008d, $0201, $00bb, $00ca, $4a01,
    $0201, $00ff, $4001, $3a01, $2001, $1001, $0801, $0401, $0201, $00ac, $00e7,
    $0201, $007e, $00d9, $0401, $0201, $009d, $00e8, $0201, $008e, $00cb, $0801,
    $0401, $0201, $00bc, $00da, $0201, $00ad, $00e9, $0401, $0201, $009e, $00cc,
    $0201, $00db, $00bd, $1001, $0801, $0401, $0201, $00ea, $00ae, $0201, $00dc,
    $00cd, $0401, $0201, $00eb, $00be, $0201, $00dd, $00ec, $0801, $0401, $0201,
    $00ce, $00ed, $0201, $00de, $00ee, $000f, $0401, $0201, $00f0, $001f, $00f1,
    $0401, $0201, $00f2, $002f, $0201, $00f3, $003f, $1201, $0801, $0401, $0201,
    $00f4, $004f, $0201, $00f5, $005f, $0401, $0201, $00f6, $006f, $0201, $00f7,
    $0201, $007f, $008f, $0a01, $0401, $0201, $00f8, $00f9, $0401, $0201, $009f,
    $00af, $00fa, $0801, $0401, $0201, $00fb, $00bf, $0201, $00fc, $00cf, $0401,
    $0201, $00fd, $00df, $0201, $00fe, $00ef,
  //},g_huffman_table_32[31] = {
    $0201, $0000, $0801, $0401, $0201, $0008, $0004, $0201, $0001, $0002, $0801,
    $0401, $0201, $000c, $000a, $0201, $0003, $0006, $0601, $0201, $0009, $0201,
    $0005, $0007, $0401, $0201, $000e, $000d, $0201, $000f, $000b,
  //},g_huffman_table_33[31] = {
    $1001, $0801, $0401, $0201, $0000, $0001, $0201, $0002, $0003, $0401, $0201,
    $0004, $0005, $0201, $0006, $0007, $0801, $0401, $0201, $0008, $0009, $0201,
    $000a, $000b, $0401, $0201, $000c, $000d, $0201, $000e, $000f
  );

  { [layer 1-3] [header bitrate_index] }
  GMpeg1Bitrates: array[0..2, 0..14] of Integer = (
    (0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000), // Layer 1
    (0, 32000, 48000, 56000,  64000,  80000,  96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000), // Layer 2
    (0, 32000, 40000, 48000,  56000,  64000,  80000,  96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000)  // Layer 3
  );

  GSamplingFrequency: array[0..2] of Integer = ( 44100 * Hz, 48000 * Hz, 32000 * Hz );
  { slen1,slen2 }
  Mpeg1ScalefacSizes: array[0..15, 0..1] of Integer = (
    (0, 0), (0, 1), (0, 2), (0,3), (3, 0), (1, 1), (1, 2), (1, 3),
    (2, 1), (2, 2), (2, 3), (3,1), (3, 2), (3, 3), (4, 2), (4, 3)
  );

  GHuffmanMain: array[0..33] of THuffTables = (
    (HuffTable:    0; TreeLen:    0; LinBits:  0),  // Table  0
    (HuffTable:    0; TreeLen:    7; LinBits:   0),  // Table  1
    (HuffTable:    7; TreeLen:   17; LinBits:   0),  // Table  2
    (HuffTable:   24; TreeLen:   17; LinBits:   0),  // Table  3
    (HuffTable:    0; TreeLen:    0; LinBits:   0),  // Table  4
    (HuffTable:   41; TreeLen:   31; LinBits:   0),  // Table  5
    (HuffTable:   72; TreeLen:   31; LinBits:   0),  // Table  6
    (HuffTable:  103; TreeLen:   71; LinBits:   0),  // Table  7
    (HuffTable:  174; TreeLen:   71; LinBits:   0),  // Table  8
    (HuffTable:  245; TreeLen:   71; LinBits:   0),  // Table  9
    (HuffTable:  316; TreeLen:  127; LinBits:   0),  // Table 10
    (HuffTable:  443; TreeLen:  127; LinBits:   0),  // Table 11
    (HuffTable:  570; TreeLen:  127; LinBits:   0),  // Table 12
    (HuffTable:  697; TreeLen:  511; LinBits:   0),  // Table 13
    (HuffTable:    0; TreeLen:    0; LinBits:   0),  // Table 14
    (HuffTable: 1208; TreeLen:  511; LinBits:   0),  // Table 15
    (HuffTable: 1719; TreeLen:  511; LinBits:   1),  // Table 16
    (HuffTable: 1719; TreeLen:  511; LinBits:   2),  // Table 17
    (HuffTable: 1719; TreeLen:  511; LinBits:   3),  // Table 18
    (HuffTable: 1719; TreeLen:  511; LinBits:   4),  // Table 19
    (HuffTable: 1719; TreeLen:  511; LinBits:   6),  // Table 20
    (HuffTable: 1719; TreeLen:  511; LinBits:   8),  // Table 21
    (HuffTable: 1719; TreeLen:  511; LinBits:  10),  // Table 22
    (HuffTable: 1719; TreeLen:  511; LinBits:  13),  // Table 23
    (HuffTable: 2230; TreeLen:  512; LinBits:   4),  // Table 24
    (HuffTable: 2230; TreeLen:  512; LinBits:   5),  // Table 25
    (HuffTable: 2230; TreeLen:  512; LinBits:   6),  // Table 26
    (HuffTable: 2230; TreeLen:  512; LinBits:   7),  // Table 27
    (HuffTable: 2230; TreeLen:  512; LinBits:   8),  // Table 28
    (HuffTable: 2230; TreeLen:  512; LinBits:   9),  // Table 29
    (HuffTable: 2230; TreeLen:  512; LinBits:  11),  // Table 30
    (HuffTable: 2230; TreeLen:  512; LinBits:  13),  // Table 31
    (HuffTable: 2742; TreeLen:   31; LinBits:   0),  // Table 32
    //(HuffTable: 2261; TreeLen:   31; LinBits:   0)   // Table 33
    (HuffTable: 2773; TreeLen:   31; LinBits:   0)   // Table 33
  );

  // ci[8]={-0.6,-0.535,-0.33,-0.185,-0.095,-0.041,-0.0142,-0.0037},
  cs: array[0..7] of Real = (0.857493, 0.881742, 0.949629, 0.983315, 0.995518, 0.999161, 0.999899, 0.999993);
  ca: array[0..7] of Real = (-0.514496, -0.471732, -0.313377, -0.181913, -0.094574, -0.040966, -0.014199, -0.003700);
  { for Stereo_Process_Intensity_Long() }
  is_ratios: array[0..5] of Real = (0.000000, 0.267949, 0.577350, 1.000000, 1.732051, 3.732051);


{$ifndef IMDCT_TABLE}
  GImdctWin: array[0..3, 0..35] of Real = (
    (0.043619, 0.130526, 0.216440, 0.300706, 0.382683, 0.461749,
     0.537300, 0.608761, 0.675590, 0.737277, 0.793353, 0.843391,
     0.887011, 0.923880, 0.953717, 0.976296, 0.991445, 0.999048,
     0.999048, 0.991445, 0.976296, 0.953717, 0.923879, 0.887011,
     0.843391, 0.793353, 0.737277, 0.675590, 0.608761, 0.537299,
     0.461748, 0.382683, 0.300706, 0.216439, 0.130526, 0.043619),
    (0.043619, 0.130526, 0.216440, 0.300706, 0.382683, 0.461749,
     0.537300, 0.608761, 0.675590, 0.737277, 0.793353, 0.843391,
     0.887011, 0.923880, 0.953717, 0.976296, 0.991445, 0.999048,
     1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
     0.991445, 0.923880, 0.793353, 0.608761, 0.382683, 0.130526,
     0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000),
    (0.130526, 0.382683, 0.608761, 0.793353, 0.923880, 0.991445,
     0.991445, 0.923880, 0.793353, 0.608761, 0.382683, 0.130526,
     0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
     0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
     0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
     0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000),
    (0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
     0.130526, 0.382683, 0.608761, 0.793353, 0.923880, 0.991445,
     1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.000000,
     0.999048, 0.991445, 0.976296, 0.953717, 0.923879, 0.887011,
     0.843391, 0.793353, 0.737277, 0.675590, 0.608761, 0.537299,
     0.461748, 0.382683, 0.300706, 0.216439, 0.130526, 0.043619)
  );
{$endif}

{$ifdef IMDCT_NTABLES}
  cos_N12: array[0..5, 0..11] of Real = (
    ( 0.608761, 0.382683, 0.130526, -0.130526, -0.382683, -0.608761,
     -0.793353, -0.923880, -0.991445, -0.991445, -0.923879, -0.793353),
    (-0.923880, -0.923879, -0.382683, 0.382684, 0.923880, 0.923879,
      0.382683, -0.382684, -0.923880, -0.923879, -0.382683, 0.382684),
    (-0.130526, 0.923880, 0.608761, -0.608762, -0.923879, 0.130526,
      0.991445, 0.382683, -0.793354, -0.793353, 0.382684, 0.991445),
    ( 0.991445, -0.382684, -0.793353, 0.793354, 0.382683, -0.991445,
      0.130527, 0.923879, -0.608762, -0.608761, 0.923880, 0.130525),
    (-0.382684, -0.382683, 0.923879, -0.923880, 0.382684, 0.382683,
     -0.923879, 0.923880, -0.382684, -0.382683, 0.923879, -0.923880),
    (-0.793353, 0.923879, -0.991445, 0.991445, -0.923880, 0.793354,
     -0.608762, 0.382684, -0.130527, -0.130525, 0.382682, -0.608761)
  );

  cos_N36: array[0..17, 0..35] of Real = (
     ( 0.675590, 0.608761, 0.537300, 0.461749, 0.382683, 0.300706,
       0.216440, 0.130526, 0.043619, -0.043619, -0.130526, -0.216440,
      -0.300706, -0.382684, -0.461749, -0.537300, -0.608762, -0.675590,
      -0.737277, -0.793353, -0.843392, -0.887011, -0.923880, -0.953717,
      -0.976296, -0.991445, -0.999048, -0.999048, -0.991445, -0.976296,
      -0.953717, -0.923879, -0.887011, -0.843391, -0.793353, -0.737277),
     (-0.793353, -0.923880, -0.991445, -0.991445, -0.923879, -0.793353,
      -0.608761, -0.382683, -0.130526, 0.130526, 0.382684, 0.608762,
       0.793354, 0.923880, 0.991445, 0.991445, 0.923879, 0.793353,
       0.608761, 0.382683, 0.130526, -0.130527, -0.382684, -0.608762,
      -0.793354, -0.923880, -0.991445, -0.991445, -0.923879, -0.793353,
      -0.608761, -0.382683, -0.130526, 0.130527, 0.382684, 0.608762),
     (-0.537299, -0.130526, 0.300706, 0.675590, 0.923880, 0.999048,
       0.887011, 0.608761, 0.216439, -0.216440, -0.608762, -0.887011,
      -0.999048, -0.923879, -0.675590, -0.300705, 0.130527, 0.537300,
       0.843392, 0.991445, 0.953717, 0.737277, 0.382683, -0.043620,
      -0.461749, -0.793354, -0.976296, -0.976296, -0.793353, -0.461748,
      -0.043618, 0.382684, 0.737278, 0.953717, 0.991445, 0.843391),
     ( 0.887011, 0.991445, 0.737277, 0.216439, -0.382684, -0.843392,
      -0.999048, -0.793353, -0.300705, 0.300706, 0.793354, 0.999048,
       0.843391, 0.382683, -0.216440, -0.737278, -0.991445, -0.887010,
      -0.461748, 0.130527, 0.675591, 0.976296, 0.923879, 0.537299,
      -0.043621, -0.608762, -0.953717, -0.953717, -0.608760, -0.043618,
       0.537301, 0.923880, 0.976296, 0.675589, 0.130525, -0.461750),
     ( 0.382683, -0.382684, -0.923880, -0.923879, -0.382683, 0.382684,
       0.923880, 0.923879, 0.382683, -0.382684, -0.923880, -0.923879,
      -0.382683, 0.382684, 0.923880, 0.923879, 0.382682, -0.382685,
      -0.923880, -0.923879, -0.382682, 0.382685, 0.923880, 0.923879,
       0.382682, -0.382685, -0.923880, -0.923879, -0.382682, 0.382685,
       0.923880, 0.923879, 0.382682, -0.382685, -0.923880, -0.923879),
     (-0.953717, -0.793353, 0.043620, 0.843392, 0.923879, 0.216439,
      -0.675591, -0.991445, -0.461748, 0.461749, 0.991445, 0.675589,
      -0.216441, -0.923880, -0.843391, -0.043618, 0.793354, 0.953717,
       0.300704, -0.608763, -0.999048, -0.537298, 0.382685, 0.976296,
       0.737276, -0.130528, -0.887012, -0.887010, -0.130524, 0.737279,
       0.976296, 0.382681, -0.537301, -0.999048, -0.608760, 0.300708),
     (-0.216439, 0.793354, 0.887010, -0.043620, -0.923880, -0.737277,
       0.300707, 0.991445, 0.537299, -0.537301, -0.991445, -0.300705,
       0.737278, 0.923879, 0.043618, -0.887012, -0.793352, 0.216441,
       0.976296, 0.608760, -0.461750, -0.999048, -0.382682, 0.675592,
       0.953716, 0.130524, -0.843393, -0.843390, 0.130529, 0.953718,
       0.675588, -0.382686, -0.999048, -0.461746, 0.608764, 0.976295),
     ( 0.991445, 0.382683, -0.793354, -0.793353, 0.382684, 0.991445,
       0.130525, -0.923880, -0.608760, 0.608763, 0.923879, -0.130528,
      -0.991445, -0.382682, 0.793354, 0.793352, -0.382685, -0.991445,
      -0.130524, 0.923880, 0.608760, -0.608763, -0.923879, 0.130529,
       0.991445, 0.382681, -0.793355, -0.793352, 0.382686, 0.991444,
       0.130523, -0.923881, -0.608759, 0.608764, 0.923878, -0.130529),
     ( 0.043619, -0.991445, -0.216439, 0.953717, 0.382682, -0.887011,
      -0.537299, 0.793354, 0.675589, -0.675591, -0.793352, 0.537301,
       0.887010, -0.382685, -0.953716, 0.216442, 0.991445, -0.043622,
      -0.999048, -0.130524, 0.976297, 0.300703, -0.923881, -0.461746,
       0.843393, 0.608759, -0.737279, -0.737275, 0.608764, 0.843390,
      -0.461752, -0.923878, 0.300709, 0.976295, -0.130530, -0.999048),
     (-0.999048, 0.130527, 0.976296, -0.300707, -0.923879, 0.461750,
       0.843391, -0.608763, -0.737276, 0.737279, 0.608760, -0.843392,
      -0.461747, 0.923880, 0.300704, -0.976297, -0.130524, 0.999048,
      -0.043622, -0.991445, 0.216442, 0.953716, -0.382686, -0.887009,
       0.537302, 0.793351, -0.675593, -0.675588, 0.793355, 0.537297,
      -0.887013, -0.382680, 0.953718, 0.216436, -0.991445, -0.043615),
     ( 0.130527, 0.923879, -0.608762, -0.608760, 0.923880, 0.130525,
      -0.991445, 0.382685, 0.793352, -0.793355, -0.382682, 0.991445,
      -0.130528, -0.923879, 0.608763, 0.608759, -0.923881, -0.130523,
       0.991444, -0.382686, -0.793351, 0.793355, 0.382680, -0.991445,
       0.130530, 0.923878, -0.608764, -0.608758, 0.923881, 0.130522,
      -0.991444, 0.382687, 0.793351, -0.793356, -0.382679, 0.991445),
     ( 0.976296, -0.608762, -0.461747, 0.999048, -0.382685, -0.675589,
       0.953717, -0.130528, -0.843390, 0.843393, 0.130524, -0.953716,
       0.675592, 0.382681, -0.999048, 0.461751, 0.608759, -0.976297,
       0.216443, 0.793351, -0.887012, -0.043616, 0.923878, -0.737280,
      -0.300702, 0.991444, -0.537303, -0.537296, 0.991445, -0.300710,
      -0.737274, 0.923881, -0.043624, -0.887009, 0.793356, 0.216435),
     (-0.300707, -0.608760, 0.999048, -0.537301, -0.382682, 0.976296,
      -0.737279, -0.130524, 0.887010, -0.887012, 0.130529, 0.737276,
      -0.976297, 0.382686, 0.537297, -0.999048, 0.608764, 0.300703,
      -0.953716, 0.793355, 0.043616, -0.843389, 0.923881, -0.216444,
      -0.675587, 0.991445, -0.461752, -0.461745, 0.991444, -0.675594,
      -0.216435, 0.923878, -0.843394, 0.043625, 0.793350, -0.953719),
     (-0.923879, 0.923880, -0.382685, -0.382682, 0.923879, -0.923880,
       0.382685, 0.382681, -0.923879, 0.923880, -0.382686, -0.382681,
       0.923878, -0.923881, 0.382686, 0.382680, -0.923878, 0.923881,
      -0.382687, -0.382680, 0.923878, -0.923881, 0.382687, 0.382679,
      -0.923878, 0.923881, -0.382688, -0.382679, 0.923878, -0.923881,
       0.382688, 0.382678, -0.923877, 0.923882, -0.382689, -0.382678),
     ( 0.461750, 0.130525, -0.675589, 0.976296, -0.923880, 0.537301,
       0.043617, -0.608760, 0.953716, -0.953718, 0.608764, -0.043622,
      -0.537297, 0.923878, -0.976297, 0.675593, -0.130530, -0.461745,
       0.887009, -0.991445, 0.737280, -0.216444, -0.382679, 0.843389,
      -0.999048, 0.793356, -0.300711, -0.300701, 0.793350, -0.999048,
       0.843394, -0.382689, -0.216434, 0.737273, -0.991444, 0.887014),
     ( 0.843391, -0.991445, 0.953717, -0.737279, 0.382685, 0.043617,
      -0.461747, 0.793352, -0.976295, 0.976297, -0.793355, 0.461751,
      -0.043623, -0.382680, 0.737275, -0.953716, 0.991445, -0.843394,
       0.537303, -0.130530, -0.300702, 0.675587, -0.923878, 0.999048,
      -0.887013, 0.608766, -0.216445, -0.216434, 0.608757, -0.887008,
       0.999048, -0.923882, 0.675595, -0.300712, -0.130520, 0.537294),
     (-0.608763, 0.382685, -0.130528, -0.130524, 0.382681, -0.608760,
       0.793352, -0.923879, 0.991444, -0.991445, 0.923881, -0.793355,
       0.608764, -0.382687, 0.130530, 0.130522, -0.382680, 0.608758,
      -0.793351, 0.923878, -0.991444, 0.991446, -0.923881, 0.793357,
      -0.608766, 0.382689, -0.130532, -0.130520, 0.382678, -0.608756,
       0.793349, -0.923877, 0.991444, -0.991446, 0.923882, -0.793358),
     (-0.737276, 0.793352, -0.843390, 0.887010, -0.923879, 0.953716,
      -0.976295, 0.991444, -0.999048, 0.999048, -0.991445, 0.976297,
      -0.953718, 0.923881, -0.887013, 0.843394, -0.793356, 0.737280,
      -0.675594, 0.608765, -0.537304, 0.461753, -0.382688, 0.300711,
      -0.216445, 0.130532, -0.043625, -0.043613, 0.130520, -0.216433,
       0.300699, -0.382677, 0.461742, -0.537293, 0.608755, -0.675585)
   );
{$endif}

  GSynthDtbl: array[0..511] of Real = (
     0.000000000,-0.000015259,-0.000015259,-0.000015259,
    -0.000015259,-0.000015259,-0.000015259,-0.000030518,
    -0.000030518,-0.000030518,-0.000030518,-0.000045776,
    -0.000045776,-0.000061035,-0.000061035,-0.000076294,
    -0.000076294,-0.000091553,-0.000106812,-0.000106812,
    -0.000122070,-0.000137329,-0.000152588,-0.000167847,
    -0.000198364,-0.000213623,-0.000244141,-0.000259399,
    -0.000289917,-0.000320435,-0.000366211,-0.000396729,
    -0.000442505,-0.000473022,-0.000534058,-0.000579834,
    -0.000625610,-0.000686646,-0.000747681,-0.000808716,
    -0.000885010,-0.000961304,-0.001037598,-0.001113892,
    -0.001205444,-0.001296997,-0.001388550,-0.001480103,
    -0.001586914,-0.001693726,-0.001785278,-0.001907349,
    -0.002014160,-0.002120972,-0.002243042,-0.002349854,
    -0.002456665,-0.002578735,-0.002685547,-0.002792358,
    -0.002899170,-0.002990723,-0.003082275,-0.003173828,
     0.003250122, 0.003326416, 0.003387451, 0.003433228,
     0.003463745, 0.003479004, 0.003479004, 0.003463745,
     0.003417969, 0.003372192, 0.003280640, 0.003173828,
     0.003051758, 0.002883911, 0.002700806, 0.002487183,
     0.002227783, 0.001937866, 0.001617432, 0.001266479,
     0.000869751, 0.000442505,-0.000030518,-0.000549316,
    -0.001098633,-0.001693726,-0.002334595,-0.003005981,
    -0.003723145,-0.004486084,-0.005294800,-0.006118774,
    -0.007003784,-0.007919312,-0.008865356,-0.009841919,
    -0.010848999,-0.011886597,-0.012939453,-0.014022827,
    -0.015121460,-0.016235352,-0.017349243,-0.018463135,
    -0.019577026,-0.020690918,-0.021789551,-0.022857666,
    -0.023910522,-0.024932861,-0.025909424,-0.026840210,
    -0.027725220,-0.028533936,-0.029281616,-0.029937744,
    -0.030532837,-0.031005859,-0.031387329,-0.031661987,
    -0.031814575,-0.031845093,-0.031738281,-0.031478882,
     0.031082153, 0.030517578, 0.029785156, 0.028884888,
     0.027801514, 0.026535034, 0.025085449, 0.023422241,
     0.021575928, 0.019531250, 0.017257690, 0.014801025,
     0.012115479, 0.009231567, 0.006134033, 0.002822876,
    -0.000686646,-0.004394531,-0.008316040,-0.012420654,
    -0.016708374,-0.021179199,-0.025817871,-0.030609131,
    -0.035552979,-0.040634155,-0.045837402,-0.051132202,
    -0.056533813,-0.061996460,-0.067520142,-0.073059082,
    -0.078628540,-0.084182739,-0.089706421,-0.095169067,
    -0.100540161,-0.105819702,-0.110946655,-0.115921021,
    -0.120697021,-0.125259399,-0.129562378,-0.133590698,
    -0.137298584,-0.140670776,-0.143676758,-0.146255493,
    -0.148422241,-0.150115967,-0.151306152,-0.151962280,
    -0.152069092,-0.151596069,-0.150497437,-0.148773193,
    -0.146362305,-0.143264771,-0.139450073,-0.134887695,
    -0.129577637,-0.123474121,-0.116577148,-0.108856201,
     0.100311279, 0.090927124, 0.080688477, 0.069595337,
     0.057617188, 0.044784546, 0.031082153, 0.016510010,
     0.001068115,-0.015228271,-0.032379150,-0.050354004,
    -0.069168091,-0.088775635,-0.109161377,-0.130310059,
    -0.152206421,-0.174789429,-0.198059082,-0.221984863,
    -0.246505737,-0.271591187,-0.297210693,-0.323318481,
    -0.349868774,-0.376800537,-0.404083252,-0.431655884,
    -0.459472656,-0.487472534,-0.515609741,-0.543823242,
    -0.572036743,-0.600219727,-0.628295898,-0.656219482,
    -0.683914185,-0.711318970,-0.738372803,-0.765029907,
    -0.791213989,-0.816864014,-0.841949463,-0.866363525,
    -0.890090942,-0.913055420,-0.935195923,-0.956481934,
    -0.976852417,-0.996246338,-1.014617920,-1.031936646,
    -1.048156738,-1.063217163,-1.077117920,-1.089782715,
    -1.101211548,-1.111373901,-1.120223999,-1.127746582,
    -1.133926392,-1.138763428,-1.142211914,-1.144287109,
     1.144989014, 1.144287109, 1.142211914, 1.138763428,
     1.133926392, 1.127746582, 1.120223999, 1.111373901,
     1.101211548, 1.089782715, 1.077117920, 1.063217163,
     1.048156738, 1.031936646, 1.014617920, 0.996246338,
     0.976852417, 0.956481934, 0.935195923, 0.913055420,
     0.890090942, 0.866363525, 0.841949463, 0.816864014,
     0.791213989, 0.765029907, 0.738372803, 0.711318970,
     0.683914185, 0.656219482, 0.628295898, 0.600219727,
     0.572036743, 0.543823242, 0.515609741, 0.487472534,
     0.459472656, 0.431655884, 0.404083252, 0.376800537,
     0.349868774, 0.323318481, 0.297210693, 0.271591187,
     0.246505737, 0.221984863, 0.198059082, 0.174789429,
     0.152206421, 0.130310059, 0.109161377, 0.088775635,
     0.069168091, 0.050354004, 0.032379150, 0.015228271,
    -0.001068115,-0.016510010,-0.031082153,-0.044784546,
    -0.057617188,-0.069595337,-0.080688477,-0.090927124,
     0.100311279, 0.108856201, 0.116577148, 0.123474121,
     0.129577637, 0.134887695, 0.139450073, 0.143264771,
     0.146362305, 0.148773193, 0.150497437, 0.151596069,
     0.152069092, 0.151962280, 0.151306152, 0.150115967,
     0.148422241, 0.146255493, 0.143676758, 0.140670776,
     0.137298584, 0.133590698, 0.129562378, 0.125259399,
     0.120697021, 0.115921021, 0.110946655, 0.105819702,
     0.100540161, 0.095169067, 0.089706421, 0.084182739,
     0.078628540, 0.073059082, 0.067520142, 0.061996460,
     0.056533813, 0.051132202, 0.045837402, 0.040634155,
     0.035552979, 0.030609131, 0.025817871, 0.021179199,
     0.016708374, 0.012420654, 0.008316040, 0.004394531,
     0.000686646,-0.002822876,-0.006134033,-0.009231567,
    -0.012115479,-0.014801025,-0.017257690,-0.019531250,
    -0.021575928,-0.023422241,-0.025085449,-0.026535034,
    -0.027801514,-0.028884888,-0.029785156,-0.030517578,
     0.031082153, 0.031478882, 0.031738281, 0.031845093,
     0.031814575, 0.031661987, 0.031387329, 0.031005859,
     0.030532837, 0.029937744, 0.029281616, 0.028533936,
     0.027725220, 0.026840210, 0.025909424, 0.024932861,
     0.023910522, 0.022857666, 0.021789551, 0.020690918,
     0.019577026, 0.018463135, 0.017349243, 0.016235352,
     0.015121460, 0.014022827, 0.012939453, 0.011886597,
     0.010848999, 0.009841919, 0.008865356, 0.007919312,
     0.007003784, 0.006118774, 0.005294800, 0.004486084,
     0.003723145, 0.003005981, 0.002334595, 0.001693726,
     0.001098633, 0.000549316, 0.000030518,-0.000442505,
    -0.000869751,-0.001266479,-0.001617432,-0.001937866,
    -0.002227783,-0.002487183,-0.002700806,-0.002883911,
    -0.003051758,-0.003173828,-0.003280640,-0.003372192,
    -0.003417969,-0.003463745,-0.003479004,-0.003479004,
    -0.003463745,-0.003433228,-0.003387451,-0.003326416,
     0.003250122, 0.003173828, 0.003082275, 0.002990723,
     0.002899170, 0.002792358, 0.002685547, 0.002578735,
     0.002456665, 0.002349854, 0.002243042, 0.002120972,
     0.002014160, 0.001907349, 0.001785278, 0.001693726,
     0.001586914, 0.001480103, 0.001388550, 0.001296997,
     0.001205444, 0.001113892, 0.001037598, 0.000961304,
     0.000885010, 0.000808716, 0.000747681, 0.000686646,
     0.000625610, 0.000579834, 0.000534058, 0.000473022,
     0.000442505, 0.000396729, 0.000366211, 0.000320435,
     0.000289917, 0.000259399, 0.000244141, 0.000213623,
     0.000198364, 0.000167847, 0.000152588, 0.000137329,
     0.000122070, 0.000106812, 0.000106812, 0.000091553,
     0.000076294, 0.000076294, 0.000061035, 0.000061035,
     0.000045776, 0.000045776, 0.000030518, 0.000030518,
     0.000030518, 0.000030518, 0.000015259, 0.000015259,
     0.000015259, 0.000015259, 0.000015259, 0.000015259
  );

  { Scale factor band indices
    One table per sample rate. Each table contains the frequency indices
    for the 12 short and 21 long scalefactor bands. The short indices
    must be multiplied by 3 to get the actual index.
    index = Sampling freq. }
  GSfBandIndices: array[0..2] of TSfBandIndices = (
    (
      l: (0,4,8,12,16,20,24,30,36,44,52,62,74,90,110,134,162,196,238,288,342,418,576);
      s: (0,4,8,12,16,22,30,40,52,66,84,106,136,192)
    ), (
      l: (0,4,8,12,16,20,24,30,36,42,50,60,72,88,106,128,156,190,230,276,330,384,576);
      s: (0,4,8,12,16,22,28,38,50,64,80,100,126,192)
    ), (
      l: (0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576);
      s: (0,4,8,12,16,22,30,42,58,78,104,138,180,192)
    )
  );

  { Samples per frame
    first dimension is MPEG Version (1 or 2) }
  GSamplesPerFrame: array[0..1, 0..2] of Integer = (
    (   // MPEG Version 2 & 2.5
      384,    // Layer1
      1152,   // Layer2
      576     // Layer3
    ),
    (   // MPEG Version 1
      384,    // Layer1
      1152,   // Layer2
      1152    // Layer3
    )
  );

{$ifdef ACS_DEBUG}
procedure dmp_fr(const hdr: TMpeg1Header);
begin
  WriteLn(Format('rate=%d sfreq=%d pad=%d mod=%d modext=%d emph=%d',
          [hdr.BitrateIndex,
           hdr.SamplingFrequency,
           hdr.PaddingBit,
           hdr.Mode,
           hdr.ModeExtension,
           hdr.Emphasis]));
end;
{$endif}

{$ifdef ACS_DEBUG}
procedure dmp_si(const hdr: TMpeg1Header; const si: TMpeg1SideInfo);
var
  nch, ch, gr: Integer;
begin
  if (hdr.mode = Ord(mpeg1ModeSingleChannel)) then
    nch := 1
  else
    nch := 2;

  WriteLn(Format('main_data_begin=%d priv_bits=%d', [si.MainDataBegin, si.PrivateBits]));
  for ch := 0 to nch-1 do
  begin
    WriteLn('scfsi ', si.scfsi[ch][0], si.scfsi[ch][1], si.scfsi[ch][2], si.scfsi[ch][3]);
    for gr := 0 to 1 do
    begin
      WriteLn(' p23l=', si.Part2_3_length[gr][ch],
              ' bv=', si.BigValues[gr][ch],
              ' gg=', si.GlobalGain[gr][ch],
              ' scfc=', si.ScalefacCompress[gr][ch],
              ' wsf=', si.WinSwitchFlag[gr][ch],
              ' bt=', si.BlockType[gr][ch]);
      if si.WinSwitchFlag[gr][ch] <> 0 then
      begin
        WriteLn(' mbf=', si.MixedBlockFlag[gr][ch],
                ' ts1=', si.TableSelect[gr][ch][0],
                ' ts2=', si.TableSelect[gr][ch][1],
                ' sbg1=', si.SubblockGain[gr][ch][0],
                ' sbg2=', si.SubblockGain[gr][ch][1],
                ' sbg3=', si.SubblockGain[gr][ch][2]);
      end
      else
      begin
        WriteLn(' ts1=', si.TableSelect[gr][ch][0],
                ' ts2=', si.TableSelect[gr][ch][1],
                ' ts3=', si.TableSelect[gr][ch][2]);
      end;
      WriteLn(' r0c=', si.Region0Count[gr][ch], ' r1c=', si.Region1Count[gr][ch]);
      WriteLn(' pf=', si.Preflag[gr][ch],
              ' scfs=', si.ScalefacScale[gr][ch],
              ' c1ts=', si.Count1TableSelect[gr][ch]);
    end;
  end;
end;
{$endif}


{$ifdef ACS_DEBUG}
procedure dmp_scf(const si: TMpeg1SideInfo; const md: TMpeg1MainData; gr, ch: Integer);
var
  sfb, win: Integer;
begin
  if (si.WinSwitchFlag[gr][ch] <> 0) and (si.BlockType[gr][ch] = 2) then
  begin
    if (si.MixedBlockFlag[gr][ch] <> 0) then
    begin
      // First the long block scalefacs
      for sfb := 0 to 7 do
      begin
        if sfb < 7 then
          Write('scfl[', sfb, ']=', md.ScalefacL[gr][ch][sfb], ' ')
        else
          WriteLn();
      end;
      // And next the short block scalefacs
      for sfb := 3 to 11 do
      begin
        for win := 0 to 2 do
        begin
          if win < 2 then
            Write('scfs[', sfb, ',', win, ']=', md.ScalefacS[gr][ch][sfb][win], ' ')
          else
            WriteLn();
        end;
      end;
    end
    else
    begin
      // Just short blocks
      for sfb := 0 to 11 do
      begin
        for win := 0 to 2 do
        begin
          if win < 2 then
            Write('scfs[', sfb, ',', win, ']=', md.ScalefacS[gr][ch][sfb][win], ' ')
          else
            WriteLn();
        end;
      end;
    end;
  end
  else
  begin
    // Just long blocks; scalefacs first
    for sfb := 0 to 20 do
    begin
      if sfb < 20 then
        Write('scfl[', sfb, ']=', md.ScalefacL[gr][ch][sfb], ' ')
      else
        WriteLn();
    end;
  end;
end;
{$endif}

{$ifdef ACS_DEBUG}
procedure dmp_huff(const md: TMpeg1MainData; gr, ch: Integer);
var
  i: Integer;
begin
  WriteLn('HUFFMAN');
  for i := 0 to 575 do
  begin
    WriteLn(i, ': ', md.ls[gr][ch][i]);
  end;
end;
{$endif}

{$ifdef ACS_DEBUG}
procedure dmp_samples(const md: TMpeg1MainData; gr, ch, tp: Integer);
var
  i, val: Integer;
  //extern double rint(double);
begin
  WriteLn('SAMPLES', tp);
  for i := 0 to 575 do
  begin
    val := Round(md.ls[gr][ch][i] * 32768.0);
    if (val >= 32768) then val := 32767;
    if (val < -32768) then val := -32768;
    WriteLn(i, ': ', val);
  end;
end;
{$endif}

{$ifdef POW34_TABLE}
procedure InitPowtab43();
var
  i: Integer;
begin
  for i := 0 to 8206 do
    powtab34[i] := Power(i, 4.0 / 3.0);
end;
{$endif}

{$ifdef IMDCT_TABLE}
procedure InitImdct();
var
  i: Integer;
begin
  { Setup the four(one for each block type) window vectors }
  for i :=  0 to 35 do GImdctWin[0][i] := Sin(C_PI / 36 * (i + 0.5)); // 0
  for i :=  0 to 17 do GImdctWin[1][i] := Sin(C_PI / 36 * (i + 0.5)); // 1
  for i := 18 to 23 do GImdctWin[1][i] := 1.0;
  for i := 24 to 29 do GImdctWin[1][i] := Sin(C_PI / 12 * (i + 0.5 - 18.0));
  for i := 30 to 35 do GImdctWin[1][i] := 0.0;
  for i :=  0 to 11 do GImdctWin[2][i] := Sin(C_PI / 12 * (i + 0.5)); //2
  for i := 12 to 35 do GImdctWin[2][i] := 0.0;
  for i :=  0 to  5 do GImdctWin[3][i] := 0.0; //3
  for i :=  6 to 11 do GImdctWin[3][i] := Sin(C_PI / 12 * (i + 0.5 - 6.0));
  for i := 12 to 17 do GImdctWin[3][i] := 1.0;
  for i := 18 to 35 do GImdctWin[3][i] := Sin(C_PI / 36 * (i + 0.5));
end;
{$endif}

{$ifdef GGAIN_TABLE}
procedure InitGlobalGainTable();
var
  i: Integer;
begin
  for i := Low(GlobalGainTable) to High(GlobalGainTable) do
    GlobalGainTable[i] := Power(2.0, 0.25 * (i - 210));
end;
{$endif}


{ Setup the n_win windowing table for polyphase subband synthesis }
procedure InitSynthNWin();
var
  i, j: Integer;
begin
  for i := 0 to 63 do
  begin
    for j := 0 to 31 do
    begin
      GSynthNWin[i][j] := Cos(((16+i) * (2*j+1)) * (Pi/64.0));
    end;
  end;
end;

{ Description: calculates y=x^(4/3) when requantizing samples.
 Parameters: TBD
 Return value: TBD
 Author: Krister Lagerström(krister@kmlager.com) }
function Requantize_Pow_43(is_pos: Word): Real;
{$if Defined(POW34_TABLE)}
begin
  {$ifdef ACS_DEBUG}
  if (is_pos > 8206) then
  begin
    Writeln('is_pos=', is_pos, ' larger than 8206!');
    is_pos := 8206;
  end;
  {$endif ACS_DEBUG}

  Result := powtab34[is_pos];
{$elseif Defined(POW34_ITERATE)}
var
  a4, a2, x, x2, x3, x_next, is_f1, is_f2, is_f3: Real;
  i: Integer;
const
  powtab34: array[32] of Real = (
    0.000000, 1.000000, 2.519842, 4.326749, 6.349605, 8.549880, 10.902724,
    13.390519, 16.000001, 18.720756, 21.544349, 24.463783, 27.473145, 30.567354,
    33.741995, 36.993185, 40.317478, 43.711792, 47.173351, 50.699637, 54.288359,
    57.937415, 61.644873, 65.408949, 69.227988, 73.100453, 77.024908, 81.000011,
    85.024502, 89.097200, 93.216988, 97.382814
  );
  coeff: array[3] of Real = (-1.030797119e+02, 6.319399834e+00, 2.395095071e-03);
begin
  // We use a table for 0<is_pos<32 since they are so common
  if(is_pos < 32) then
  begin
    Result := powtab34[is_pos];
    Exit;
  end;
  a2 := is_pos * is_pos;
  a4 := a2 * a2;
  is_f1 := is_pos;
  is_f2 := is_f1 * is_f1;
  is_f3 := is_f1 * is_f2;
  //  x = coeff[0] + coeff[1]*is_f1 + coeff[2]*is_f2 + coeff[3]*is_f3;
  x := coeff[0] + coeff[1]*is_f1 + coeff[2]*is_f2;
  for i := 0  to 2 do
  begin
    x2 := x*x;
    x3 := x*x2;
    x_next := (2*x3 + a4) / (3*x2);
    x := x_next;
  end;
  Result := x;
{$else}
begin
  // no optimization
  Result := Power(is_pos, 4.0 / 3.0);
{$endif} // POW34_TABLE || POW34_ITERATE
end;

{ Number of channels(1 for mono and 2 for stereo) }
function GetChanCount(const id: TPdmp3Handle): Integer; inline;
begin
  if (id.GFrameHeader.Mode = Ord(mpeg1ModeSingleChannel)) then
    Result := 1
  else
    Result := 2;
end;

{ Calculate header audio data size }
function GetFrameSize(const id: TPdmp3Handle): Integer; inline;
begin
  Result := (144 * GMpeg1Bitrates[id.GFrameHeader.Layer-1][id.GFrameHeader.BitrateIndex])
          div GSamplingFrequency[id.GFrameHeader.SamplingFrequency]
          + id.GFrameHeader.PaddingBit;
end;

{ Return number of samples per single frame }
function GetSamplesPerFrame(const id: TPdmp3Handle): Integer;
begin
  Result := GSamplesPerFrame[id.GFrameHeader.Version, id.GFrameHeader.Layer-1]
end;

function Get_Inbuf_Filled(const id: TPdmp3Handle): Integer;
begin
  if (id.IStart <= id.IEnd) then
    Result := (id.IEnd - id.IStart)
  else
    Result := (INBUF_SIZE - id.IStart + id.IEnd);
end;

function Get_Inbuf_Free(const id: TPdmp3Handle): Integer;
begin
  if (id.IEnd < id.IStart) then
    Result := (id.IStart - id.IEnd)
  else
    Result := (INBUF_SIZE - id.IEnd + id.IStart);
end;

{ Description: returns next byte from bitstream, or EOF.
  If we're not on an byte-boundary, bits remaining until next boundary are
  discarded before getting that byte.
 Parameters: Stream handle.
 Return value: The next byte in bitstream in the lowest 8 bits,or C_EOF.
 Original Author: Krister Lagerström(krister@kmlager.com)
 Author: Erik Hofman(erik@ehofman.com) }
function Get_Byte(var id: TPdmp3Handle; out AValue: Byte): Integer;
begin
  Result := C_EOF;
  if (id.IStart <> id.IEnd) then
  begin
    AValue := id._in[id.IStart]; //  && 0xff;
    Inc(id.IStart);
    Result := AValue;
    if (id.IStart = INBUF_SIZE) then
      id.IStart := 0;
    Inc(id.Processed);
  end;
end;

{ Description: reads 'no_of_bytes' from input stream into 'data_vec[]'.
   Parameters: Stream handle,number of bytes to read,vector pointer where to
               store them.
   Return value: PDMP3_OK or PDMP3_ERR if the operation couldn't be performed.
   Author: Krister Lagerström(krister@kmlager.com) }
function Get_Bytes(var id: TPdmp3Handle; no_of_bytes: Integer; var data_vec): Integer;
var
  i, val: Integer;
  bt: Byte;
  p: PByte;
begin
  p := @data_vec;
  for i := 0 to no_of_bytes-1 do
  begin
    val := Get_Byte(id, bt);
    if (val = C_EOF) then
    begin
      Result := C_EOF;
      Exit;
    end
    else
    begin
      p^ := bt;
      Inc(p);
    end;
  end;
  Result := PDMP3_OK;
end;

{ Description: returns current file position in bytes.
  Parameters: Stream handle.
  Return value: File pos in bytes,or 0 if no file open.
  Original Author: Krister Lagerström(krister@kmlager.com)
  Author: Erik Hofman(erik@ehofman.com) }
function Get_Filepos(var id: TPdmp3Handle): Integer; inline;
begin
  Result := id.Processed;
end;

{ Description: gets one bit from the local buffer which contains main_data.
  Parameters: Stream handle.
  Return value: The bit is returned in the LSB of the return value.
  Author: Krister Lagerström(krister@kmlager.com) }
function Get_Main_Bit(var id: TPdmp3Handle): Integer;
begin
  //Result := id.GMainDataPtr^ shr (7 - id.GMainDataIdx);
  Result := id.GMainDataVec[id.GMainDataPos] shr (7 - id.GMainDataIdx);
  Result := Result and $01;
  //Inc(id.GMainDataPtr, (id.GMainDataIdx + 1) shr 3);
  Inc(id.GMainDataPos, (id.GMainDataIdx + 1) shr 3);
  id.GMainDataIdx := (id.GMainDataIdx + 1) and $07;
  // Done
end;

{ Description: reads 'number_of_bits' from local buffer containing main_data.
  Parameters: Stream handle,number_of_bits to read(max 24)
  Return value: The bits are returned in the LSB of the return value. }
function Get_Main_Bits(var id: TPdmp3Handle; number_of_bits: Integer): LongWord;
var
  p: PByte;
begin
  Result := 0;
  if (number_of_bits = 0) then Exit;

  { Form a word of the next four bytes }
  //p := id.GMainDataPtr;
  p := Addr(id.GMainDataVec[id.GMainDataPos]);
  Result := Result or (p^ shl 24);
  Inc(p);
  Result := Result or (p^ shl 16);
  Inc(p);
  Result := Result or (p^ shl 8);
  Inc(p);
  Result := Result or (p^ shl 0);

  { Remove bits already used }
  Result := Result shl id.GMainDataIdx;

  { Remove bits after the desired bits }
  Result := Result shr (32 - number_of_bits);

  { Update pointers }
  //Inc(id.GMainDataPtr, (id.GMainDataIdx + number_of_bits) shr 3);
  Inc(id.GMainDataPos, (id.GMainDataIdx + number_of_bits) shr 3);
  id.GMainDataIdx := (id.GMainDataIdx + number_of_bits) and $07;
  // Done
end;

{ Description: returns pos. of next bit to be read from main data bitstream.
  Parameters: Stream handle.
  Return value: Bit position.
  Author: Krister Lagerström(krister@kmlager.com) }
function Get_Main_BitPos(var id: TPdmp3Handle): Integer;
begin
  //Result := PtrUInt(id.GMainDataPtr) - PtrUInt(Addr(id.GMainDataVec[0]));
  Result := id.GMainDataPos;
  //Result := Result div 4; // Divide by four to get number of bytes
  Result := Result * 8; // Multiply by 8 to get number of bits
  Result := Result + id.GMainDataIdx;  // Add current bit index
end;

{ Description: sets position of next bit to be read from main data bitstream.
  Parameters: Stream handle,Bit position. 0 = start,8 = start of byte 1,etc.
  Return value: PDMP3_OK or PDMP3_ERR if bit_pos is past end of main data for this frame.
  Author: Krister Lagerström(krister@kmlager.com) }
function Set_Main_Pos(var id: TPdmp3Handle; bit_pos: Integer): Integer;
begin
  //id.GMainDataPtr := Addr(id.GMainDataVec[bit_pos shr 3]);
  id.GMainDataPos := bit_pos shr 3;
  id.GMainDataIdx := bit_pos and $07;
  Result := PDMP3_OK;
end;

{ Description: reads 'number_of_bits' from buffer which contains side_info.
  Parameters: Stream handle,number_of_bits to read(max 16)
  Return value: The bits are returned in the LSB of the return value.
  Author: Krister Lagerström(krister@kmlager.com) }
function Get_Side_Bits(var id: TPdmp3Handle; number_of_bits: Integer): LongWord;
var
  p: PByte;
begin
  { Form a word of the next four bytes }
  { TODO: endianness }
  p := id.SideInfoPtr;
  Result := 0;
  Result := Result or (p^ shl 24);
  Inc(p);
  Result := Result or (p^ shl 16);
  Inc(p);
  Result := Result or (p^ shl 8);
  Inc(p);
  Result := Result or (p^ shl 0);
  { Remove bits already used }
  Result := Result shl id.SideInfoIdx;
  { Remove bits after the desired bits }
  Result := Result shr (32 - number_of_bits);
  { Update pointers }
  Inc(id.SideInfoPtr, (id.SideInfoIdx + number_of_bits) shr 3);
  id.SideInfoIdx := (id.SideInfoIdx + number_of_bits) and $07;
end;

{ Description: This function assembles the main data buffer with data from
               this frame and the previous two frames into a local buffer
               used by the Get_Main_Bits function.
  Parameters: Stream handle,main_data_begin indicates how many bytes from
              previous frames that should be used. main_data_size indicates the
              number of data bytes in this frame.
  Return value: Status
  Author: Krister Lagerström(krister@kmlager.com) }
function Get_Main_Data(var id: TPdmp3Handle; main_data_size: Integer; main_data_begin: Integer): Integer;
var
  i: Integer;
begin
  {$ifdef ACS_DEBUG}
  if (main_data_size > 1500) then
    WriteLn('main_data_size = ', main_data_size);
  {$endif}
  { Check that there's data available from previous frames if needed }
  if (main_data_begin > id.GMainDataTop) then
  begin
    { No,there is not, so we skip decoding this frame,but we have to
      read the main_data bits from the bitstream in case they are needed
      for decoding the next frame. }
    Get_Bytes(id, main_data_size, id.GMainDataVec[id.GMainDataTop]);
    // Set up pointers
    //id.GMainDataPtr := Addr(id.GMainDataVec[0]);
    id.GMainDataPos := 0;
    id.GMainDataIdx := 0;
    id.GMainDataTop := id.GMainDataTop + main_data_size;
    // This frame cannot be decoded!
    Result := PDMP3_NEED_MORE;
    Exit;
  end;
  for i := 0 to main_data_begin-1 do
  begin
    // Copy data from previous frames
    id.GMainDataVec[i] := id.GMainDataVec[id.GMainDataTop - main_data_begin + i];
  end;
  { Read the main_data from file }
  Get_Bytes(id, main_data_size, id.GMainDataVec[main_data_begin]);
  { Set up pointers }
  //id.GMainDataPtr := Addr(id.GMainDataVec[0]);
  id.GMainDataPos := 0;
  id.GMainDataIdx := 0;
  id.GMainDataTop := main_data_begin + main_data_size;
  // Done
  Result := PDMP3_OK;
end;

{ Description: Reads sideinfo from bitstream into buffer for Get_Side_Bits.
 Parameters: Stream handle,TBD
 Return value: TBD
 Author: Krister Lagerström(krister@kmlager.com) }
procedure Get_Sideinfo(var id: TPdmp3Handle; sideinfo_size: Integer);
begin
  if (Get_Bytes(id, sideinfo_size, id.SideInfoVec) <> PDMP3_OK) then
  begin
    {$ifdef ACS_DEBUG}
    WriteLn();
    WriteLn('Couldn''t read sideinfo ', sideinfo_size, ' bytes at pos ', Get_Filepos(id));
    {$endif}
    Exit;
  end;

  id.SideInfoPtr := Addr(id.SideInfoVec[0]);
  id.SideInfoIdx := 0;
end;

{ Description: Reads audio and main data from bitstream into a buffer. main
  data is taken from this frame and up to 2 previous frames.
 Parameters: Stream handle.
 Return value: PDMP3_OK or PDMP3_ERR if data could not be read,or contains errors.
 Author: Krister Lagerström(krister@kmlager.com) }
function Read_Audio_L3(var id: TPdmp3Handle): Integer;
var
  framesize, sideinfo_size, main_data_size: Integer;
  nch, ch, gr, scfsi_band, region, window: Integer;
begin
  { Number of channels(1 for mono and 2 for stereo) }
  nch := GetChanCount(id);
  { Calculate header audio data size }
  framesize := GetFrameSize(id);
  if (framesize > 2000) then
  begin
    {$ifdef ACS_DEBUG}WriteLn('framesize=', framesize); {$endif}
    Result := PDMP3_ERR;
    Exit;
  end;
  { Sideinfo is 17 bytes for one channel and 32 bytes for two }
  if (nch = 1) then
    sideinfo_size := 17
  else
    sideinfo_size := 32;
  { Main data size is the rest of the frame,including ancillary data }
  main_data_size := framesize - sideinfo_size - 4; // sync+header
  { CRC is 2 bytes }
  if (id.GFrameHeader.ProtectionBit = 0) then
    main_data_size := main_data_size - 2;
  { WriteLn('framesize      =   ', framesize); }
  { WriteLn('sideinfo_size  =   ', sideinfo_size); }
  { WriteLn('main_data_size =   ', main_data_size); }
  { Read sideinfo from bitstream into buffer used by Get_Side_Bits() }
  Get_Sideinfo(id, sideinfo_size);
  if (Get_Filepos(id) = C_EOF) then
  begin
    Result := PDMP3_ERR;
    Exit;
  end;
  { Parse audio data }
  { Pointer to where we should start reading main data }
  id.GSideInfo.MainDataBegin := Get_Side_Bits(id, 9);
  { Get private bits. Not used for anything. }
  if (id.GFrameHeader.Mode = Ord(mpeg1ModeSingleChannel)) then
    id.GSideInfo.PrivateBits := Get_Side_Bits(id, 5)
  else
    id.GSideInfo.PrivateBits := Get_Side_Bits(id, 3);
  { Get scale factor selection information }
  for ch := 0 to nch-1 do
  begin
    for scfsi_band := 0 to 4-1 do
    begin
      id.GSideInfo.Scfsi[ch][scfsi_band] := Get_Side_Bits(id, 1);
    end;
  end;
  { Get the rest of the side information }
  for gr := 0 to 1 do
  begin
    for ch := 0 to nch-1 do
    begin
      id.GSideInfo.Part2_3_length[gr][ch]    := Get_Side_Bits(id, 12);
      id.GSideInfo.BigValues[gr][ch]         := Get_Side_Bits(id, 9);
      id.GSideInfo.GlobalGain[gr][ch]        := Get_Side_Bits(id, 8);
      id.GSideInfo.ScalefacCompress[gr][ch]  := Get_Side_Bits(id, 4);
      id.GSideInfo.WinSwitchFlag[gr][ch]     := Get_Side_Bits(id, 1);
      if (id.GSideInfo.WinSwitchFlag[gr][ch] = 1) then
      begin
        id.GSideInfo.BlockType[gr][ch]       := Get_Side_Bits(id, 2);
        id.GSideInfo.MixedBlockFlag[gr][ch]  := Get_Side_Bits(id, 1);
        for region := 0 to 1 do
          id.GSideInfo.TableSelect[gr][ch][region] := Get_Side_Bits(id, 5);
        for window := 0 to 2 do
          id.GSideInfo.SubblockGain[gr][ch][window] := Get_Side_Bits(id, 3);
        if ((id.GSideInfo.BlockType[gr][ch] = 2) and (id.GSideInfo.MixedBlockFlag[gr][ch] = 0)) then
          id.GSideInfo.Region0Count[gr][ch] := 8 // Implicit
        else
          id.GSideInfo.Region0Count[gr][ch] := 7; // Implicit
        { The standard is wrong on this!!! }   // Implicit
        id.GSideInfo.Region1Count[gr][ch] := 20 - id.GSideInfo.Region0Count[gr][ch];
      end
      else
      begin
        for region := 0 to 2 do
          id.GSideInfo.TableSelect[gr][ch][region] := Get_Side_Bits(id, 5);
        id.GSideInfo.Region0Count[gr][ch] := Get_Side_Bits(id, 4);
        id.GSideInfo.Region1Count[gr][ch] := Get_Side_Bits(id, 3);
        id.GSideInfo.BlockType[gr][ch] := 0;  // Implicit
      end;
      id.GSideInfo.Preflag[gr][ch]           := Get_Side_Bits(id, 1);
      id.GSideInfo.ScalefacScale[gr][ch]     := Get_Side_Bits(id, 1);
      id.GSideInfo.Count1TableSelect[gr][ch] := Get_Side_Bits(id, 1);
    end;
  end;
  Result := PDMP3_OK; // Done
end;

{ Description: Reads 16 CRC bits
  Parameters: Stream handle.
  Return value: PDMP3_OK or PDMP3_ERR if CRC could not be read.
  Author: Krister Lagerström(krister@kmlager.com) }
function Read_CRC(var id: TPdmp3Handle): Integer;
var
  bt: Byte;
begin
  { Get next two bytes from bitstream, If we got an End Of File we're done }
  if ((Get_Byte(id, bt) = C_EOF) or (Get_Byte(id, bt) = C_EOF)) then
    Result := PDMP3_ERR
  else
    Result := PDMP3_OK;
end;

{ Description: reads/decodes next Huffman code word from main_data reservoir.
  Parameters: Stream handle,Huffman table number and four pointers for the
              return values.
  Return value: Two(x,y) or four(x,y,v,w) decoded Huffman words.
  Author: Krister Lagerström(krister@kmlager.com) }
function Huffman_Decode(var id: TPdmp3Handle; table_num: Integer; out x, y, v, w: LongInt): Integer;
var
  point, error, BitsLeft, TreeLen, LinBits: Integer;
  htPtr: Word;
begin
  point := 0;
  error := 1;
  bitsleft := 32; //=16??
  TreeLen := GHuffmanMain[table_num].TreeLen;
  LinBits := GHuffmanMain[table_num].LinBits;

  if (TreeLen = 0) then
  begin
    { Check for empty tables }
    x := 0;
    y := 0;
    v := 0;
    w := 0;
    Result := PDMP3_OK;
    Exit;
  end;

  htPtr := GHuffmanMain[table_num].Hufftable;
  while (BitsLeft > 0) and (point < TreeLen) do
  begin
    { Start reading the Huffman code word, bit by bit }
    { Check if we've matched a code word }
    if ((GHuffmanTable[htptr + point] and $ff00) = 0) then
    begin
      error := 0;
      x := (GHuffmanTable[htptr + point] shr 4) and $0f;
      y := GHuffmanTable[htptr + point] and $0f;
      Break;
    end;

    if (Get_Main_Bit(id) <> 0) then
    begin
      { Go right in tree }
      while ((GHuffmanTable[htptr + point] and $ff) >= 250) do
        point := point + GHuffmanTable[htptr + point] and $ff;
      point := point + GHuffmanTable[htptr + point] and $ff;
    end
    else
    begin
      { Go left in tree }
      while ((GHuffmanTable[htptr + point] shr 8) >= 250) do
        point := point + (GHuffmanTable[htptr + point] shr 8);
      point := point + (GHuffmanTable[htptr + point] shr 8);
    end;
    Dec(BitsLeft);
  end;

  if (error <> 0) then
  begin
    { Check for error. }
    {$ifdef ACS_DEBUG}
    WriteLn('Illegal Huff code in data. bleft=', BitsLeft,
            ', point=', point,
            '. tab=', table_num);
    {$endif}
    x := 0;
    y := 0;
  end;

  if (table_num > 31) then
  begin
    { Process sign encodings for quadruples tables. }
    v := (y shr 3) and 1;
    w := (y shr 2) and 1;
    x := (y shr 1) and 1;
    y := y and 1;
    if ((v > 0) and (Get_Main_Bit(id) = 1)) then
      v := -v;
    if ((w > 0) and (Get_Main_Bit(id) = 1)) then
      w := -w;
    if ((x > 0) and (Get_Main_Bit(id) = 1)) then
      x := -x;
    if ((y > 0) and (Get_Main_Bit(id) = 1)) then
      y := -y;
  end
  else
  begin
    if ((LinBits > 0) and (x = 15)) then
      x := x + Get_Main_Bits(id, LinBits); // Get LinBits
    if ((x > 0) and (Get_Main_Bit(id) = 1)) then
      x := -x; // Get sign bit
    if ((LinBits > 0) and (y = 15)) then
      y := y + Get_Main_Bits(id, LinBits); // Get LinBits
    if ((y > 0) and (Get_Main_Bit(id) = 1)) then
      y := -y; // Get sign bit
  end;

  if Error <> 0 then
    Result := PDMP3_ERR
  else
    Result := PDMP3_OK;
end;

{ Description: called by Read_Main_L3 to read Huffman coded data from bitstream.
  Parameters: Stream handle,TBD
  Return value: None. The data is stored in id->g_main_data.is[ch][gr][freqline].
  Author: Krister Lagerström(krister@kmlager.com) }
procedure Read_Huffman(var id: TPdmp3Handle; part_2_start, gr, ch: Integer);
var
  x, y, v, w: LongInt;
  table_num, ls_pos, bit_pos_end, sfreq, bit_pos: Integer;
  region_1_start, region_2_start: Integer; { region_0_start = 0 }
begin
  { Check that there is any data to decode. If not,zero the array. }
  if (id.GSideInfo.Part2_3_length[gr][ch] = 0) then
  begin
    for ls_pos := 0 to 575 do
      id.GMainData.ls[gr][ch][ls_pos] := 0.0;
    Exit;
  end;
  { Calculate bit_pos_end which is the index of the last bit for this part. }
  bit_pos_end := part_2_start + id.GSideInfo.Part2_3_length[gr][ch] - 1;
  { Determine region boundaries }
  if ((id.GSideInfo.WinSwitchFlag[gr][ch] = 1) and (id.GSideInfo.BlockType[gr][ch] = 2)) then
  begin
    region_1_start := 36;  // sfb[9/3]*3=36
    region_2_start := 576; // No Region2 for short block case.
  end
  else
  begin
    sfreq := id.GFrameHeader.SamplingFrequency;
    region_1_start := GSfBandIndices[sfreq].l[id.GSideInfo.Region0Count[gr][ch] + 1];
    region_2_start := GSfBandIndices[sfreq].l[id.GSideInfo.Region0Count[gr][ch] + id.GSideInfo.Region1Count[gr][ch] + 2];
  end;
  { Read big_values using tables according to region_x_start }
  ls_pos := 0;
  while ls_pos < (id.GSideInfo.BigValues[gr][ch] * 2) do
  begin
    if (ls_pos < region_1_start) then
      table_num := id.GSideInfo.TableSelect[gr][ch][0]
    else if (ls_pos < region_2_start) then
      table_num := id.GSideInfo.TableSelect[gr][ch][1]
    else
      table_num := id.GSideInfo.TableSelect[gr][ch][2];
    { Get next Huffman coded words }
    Huffman_Decode(id, table_num, x, y, v, w);
    { In the big_values area there are two freq lines per Huffman word }
    id.GMainData.ls[gr][ch][ls_pos] := x;
    Inc(ls_pos);
    id.GMainData.ls[gr][ch][ls_pos] := y;
    Inc(ls_pos);
  end;
  { Read small values until ls_pos = 576 or we run out of huffman data }
  table_num := id.GSideInfo.Count1TableSelect[gr][ch] + 32;
  ls_pos := id.GSideInfo.BigValues[gr][ch] * 2;
  bit_pos := Get_Main_BitPos(id);
  while (ls_pos <= 572) and (bit_pos < bit_pos_end) do
  begin
    { Get next Huffman coded words }
    Huffman_Decode(id, table_num, x, y, v, w);
    id.GMainData.ls[gr][ch][ls_pos] := v;
    Inc(ls_pos);
    if (ls_pos >= 576) then Break;
    id.GMainData.ls[gr][ch][ls_pos] := w;
    Inc(ls_pos);
    if (ls_pos >= 576) then Break;
    id.GMainData.ls[gr][ch][ls_pos] := x;
    Inc(ls_pos);
    if (ls_pos >= 576) then Break;
    id.GMainData.ls[gr][ch][ls_pos] := y;
    Inc(ls_pos);
    bit_pos := Get_Main_BitPos(id);
  end;
  { Check that we didn't read past the end of this section }
  if (Get_Main_BitPos(id) > (bit_pos_end + 1)) then // Remove last words read
    ls_pos := ls_pos - 4;
  { Setup count1 which is the index of the first sample in the rzero reg. }
  id.GSideInfo.Count1[gr][ch] := ls_pos;
  { Zero out the last part if necessary }
  while ls_pos < 576 do
  begin
    id.GMainData.ls[gr][ch][ls_pos] := 0.0;
    Inc(ls_pos);
  end;
  { Set the bitpos to point to the next part to read }
  Set_Main_Pos(id, bit_pos_end + 1);
  // Done
end;

{ Description: reads main data for layer 3 from main_data bit reservoir.
  Parameters: Stream handle.
  Return value: PDMP3_OK or PDMP3_ERR if the data contains errors.
  Author: Krister Lagerström(krister@kmlager.com) }
function Read_Main_L3(var id: TPdmp3Handle): Integer;
var
  framesize, sideinfo_size, main_data_size: Integer;
  gr, ch, nch, sfb, win, slen1, slen2, nbits, part_2_start: Integer;
begin
  { Number of channels(1 for mono and 2 for stereo) }
  nch := GetChanCount(id);

  { Calculate header audio data size }
  framesize := GetFrameSize(id);

  if(framesize > 2000) then
  begin
    {$ifdef ACS_DEBUG}WriteLn('framesize=', framesize);{$endif}
    Result := PDMP3_ERR;
    Exit;
  end;
  { Sideinfo is 17 bytes for one channel and 32 bytes for two }
  if nch = 1 then
    sideinfo_size := 17
  else
    sideinfo_size := 32;
  { Main data size is the rest of the frame,including ancillary data }
  main_data_size := framesize - sideinfo_size - 4; // sync+header
  { CRC is 2 bytes }
  if (id.GFrameHeader.ProtectionBit = 0) then
    main_data_size := main_data_size - 2;
  { Assemble main data buffer with data from this frame and the previous
    two frames. main_data_begin indicates how many bytes from previous
    frames that should be used. This buffer is later accessed by the
    Get_Main_Bits function in the same way as the side info is. }
  Result := Get_Main_Data(id, main_data_size, id.GSideInfo.MainDataBegin);
  if (Result <> PDMP3_OK) then
  begin
    { This could be due to not enough data in reservoir }
    Exit;
  end;
  { TODO: check that main data is sound data }
  for gr := 0 to 1 do
  begin
    for ch := 0 to nch-1 do
    begin
      part_2_start := Get_Main_BitPos(id);
      { Number of bits in the bitstream for the bands }
      slen1 := Mpeg1ScalefacSizes[id.GSideInfo.ScalefacCompress[gr][ch]][0];
      slen2 := Mpeg1ScalefacSizes[id.GSideInfo.ScalefacCompress[gr][ch]][1];
      { Read scalefactors }
      if ((id.GSideInfo.WinSwitchFlag[gr][ch] <> 0) and (id.GSideInfo.BlockType[gr][ch] = 2)) then
      begin
        // short block
        if (id.GSideInfo.MixedBlockFlag[gr][ch] <> 0) then
        begin
          for sfb := 0 to 7 do
            id.GMainData.ScalefacL[gr][ch][sfb] := Get_Main_Bits(id, slen1);
          for sfb := 3 to 11 do
          begin
            if (sfb < 6) then
              nbits := slen1
            else
              nbits := slen2;
            { slen1 for band 3-5, slen2 for 6-11 }
            for win := 0 to 2 do
              id.GMainData.ScalefacS[gr][ch][sfb][win] := Get_Main_Bits(id, nbits);
          end;
        end
        else
        begin
          for sfb := 0 to 11 do
          begin
            if (sfb < 6) then
              nbits := slen1
            else
              nbits := slen2;
            { slen1 for band 3-5, slen2 for 6-11 }
            for win := 0 to 2 do
              id.GMainData.ScalefacS[gr][ch][sfb][win] := Get_Main_Bits(id, nbits);
          end;
        end;
      end
      else
      begin
        { block_type == 0 if winswitch == 0 }
        { Scale factor bands 0-5 }
        if ((id.GSideInfo.Scfsi[ch][0] = 0) or (gr = 0)) then
        begin
          for sfb := 0 to 5 do
            id.GMainData.ScalefacL[gr][ch][sfb] := Get_Main_Bits(id, slen1);
        end
        else if ((id.GSideInfo.Scfsi[ch][0] = 1) and (gr = 1)) then
        begin
          { Copy scalefactors from granule 0 to granule 1 }
          for sfb := 0 to 5 do
            id.GMainData.ScalefacL[1][ch][sfb] := id.GMainData.ScalefacL[0][ch][sfb];
        end;

        { Scale factor bands 6-10 }
        if ((id.GSideInfo.Scfsi[ch][1] = 0) or (gr = 0)) then
        begin
          for sfb := 6 to 10 do
            id.GMainData.ScalefacL[gr][ch][sfb] := Get_Main_Bits(id, slen1);
        end
        else if ((id.GSideInfo.Scfsi[ch][1] = 1) and (gr = 1)) then
        begin
          { Copy scalefactors from granule 0 to granule 1 }
          for sfb := 6 to 10 do
            id.GMainData.ScalefacL[1][ch][sfb] := id.GMainData.ScalefacL[0][ch][sfb];
        end;

        { Scale factor bands 11-15 }
        if ((id.GSideInfo.Scfsi[ch][2] = 0) or (gr = 0)) then
        begin
          for sfb := 11 to 15 do
            id.GMainData.ScalefacL[gr][ch][sfb] := Get_Main_Bits(id, slen2);
        end
        else if((id.GSideInfo.Scfsi[ch][2] = 1) and (gr = 1)) then
        begin
          { Copy scalefactors from granule 0 to granule 1 }
          for sfb := 11 to 15 do
            id.GMainData.ScalefacL[1][ch][sfb] := id.GMainData.ScalefacL[0][ch][sfb];
        end;

        { Scale factor bands 16-20 }
        if ((id.GSideInfo.Scfsi[ch][3] = 0) or (gr = 0)) then
        begin
          for sfb := 16 to 20 do
            id.GMainData.ScalefacL[gr][ch][sfb] := Get_Main_Bits(id, slen2);
        end
        else if((id.GSideInfo.Scfsi[ch][3] = 1) and (gr = 1)) then
        begin
          { Copy scalefactors from granule 0 to granule 1 }
          for sfb := 16 to 20 do
            id.GMainData.ScalefacL[1][ch][sfb] := id.GMainData.ScalefacL[0][ch][sfb];
        end;
      end;
      { Read Huffman coded data. Skip stuffing bits. }
      Read_Huffman(id, part_2_start, gr, ch);
    end;
  end;
  { The ancillary data is stored here, but we ignore it. }
  Result := PDMP3_OK;
end;

{ Description: Scans bitstream for syncword until we find it or EOF. The
   syncword must be byte-aligned. It then reads and parses audio header.
  Parameters: Stream handle.
  Return value: PDMP3_OK or PDMP3_ERR if the syncword can't be found,or the header
                contains impossible values.
  Author: Krister Lagerström(krister@kmlager.com) }
function Read_Header(var id: TPdmp3Handle): Integer;
var
  b1, b2, b3, b4: Integer;
  bt1, bt2, bt3, bt4: Byte;
  header: LongWord;
begin
  Result := PDMP3_ERR;
  { Get the next four bytes from the bitstream }
  b1 := Get_Byte(id, bt1);
  b2 := Get_Byte(id, bt2);
  b3 := Get_Byte(id, bt3);
  b4 := Get_Byte(id, bt4);
  { If we got an End Of File condition we're done }
  if ((b1 = C_EOF) or (b2 = C_EOF) or (b3 = C_EOF) or (b4 = C_EOF)) then
    Exit;

  header := (bt1 shl 24) or (bt2 shl 16) or (bt3 shl 8) or (bt4 shl 0);
  { Are the high 12 bits the syncword(0xfff)? }
  while ((header and $fff00000) <> C_SYNC) do
  begin
    { No, so scan the bitstream one byte at a time until we find it or EOF }
    { Shift the values one byte to the left }
    bt1 := bt2;
    bt2 := bt3;
    bt3 := bt4;
    { Get one new byte from the bitstream }
    b4 := Get_Byte(id, bt4);
    { If we got an End Of File condition we're done }
    if (b4 = C_EOF) then
      Exit;
    { Make up the new header }
    header := (bt1 shl 24) or (bt2 shl 16) or (bt3 shl 8) or (bt4 shl 0);
  end;
  { If we get here we've found the sync word,and can decode the header
    which is in the low 20 bits of the 32-bit sync+header word. }
  { Decode the header }
  id.GFrameHeader.Version            := (header and $00100000) shr 20;
  id.GFrameHeader.Id                 := (header and $00080000) shr 19;
  id.GFrameHeader.Layer              := (header and $00060000) shr 17;
  id.GFrameHeader.ProtectionBit      := (header and $00010000) shr 16;
  id.GFrameHeader.BitrateIndex       := (header and $0000f000) shr 12;
  id.GFrameHeader.SamplingFrequency  := (header and $00000c00) shr 10;
  id.GFrameHeader.PaddingBit         := (header and $00000200) shr 9;
  id.GFrameHeader.PrivateBit         := (header and $00000100) shr 8;
  id.GFrameHeader.Mode               := (header and $000000c0) shr 6;
  id.GFrameHeader.ModeExtension      := (header and $00000030) shr 4;
  id.GFrameHeader.Copyright          := (header and $00000008) shr 3;
  id.GFrameHeader.Original           := (header and $00000004) shr 2;
  id.GFrameHeader.Emphasis           := (header and $00000003) shr 0;
  { Check for invalid values and impossible combinations }
  if (id.GFrameHeader.Id <> 1) then
  begin
    WriteLn('ID must be 1');
    WriteLn('Header=', IntToHex(header, 8), ' at file pos ', Get_Filepos(id));
    Exit;
  end;
  if (id.GFrameHeader.BitrateIndex = 0) then
  begin
    WriteLn('Free bitrate format NIY!');
    WriteLn('Header=', IntToHex(header, 8), ' at file pos ', Get_Filepos(id));
    Exit;
  end;
  if (id.GFrameHeader.BitrateIndex = 15) then
  begin
    WriteLn('bitrate_index = 15 is invalid!');
    WriteLn('Header=', IntToHex(header, 8), ' at file pos ', Get_Filepos(id));
    Exit;
  end;
  if (id.GFrameHeader.SamplingFrequency = 3) then
  begin
    WriteLn('sampling_frequency = 3 is invalid!');
    WriteLn('Header=', IntToHex(header, 8), ' at file pos ', Get_Filepos(id));
    Exit;
  end;
  if (id.GFrameHeader.Layer = 0) then
  begin
    WriteLn('layer = 0 is invalid!');
    WriteLn('Header=', IntToHex(header, 8), ' at file pos ', Get_Filepos(id));
    Exit;
  end;

  id.GFrameHeader.layer := 4 - id.GFrameHeader.layer;
  { WriteLn('Header=', IntToHex(header, 8)); }
  if (id.NewHeader <> 0) then
    id.NewHeader := 1;

  Result := PDMP3_OK;
end;

function Search_Header(var id: TPdmp3Handle): Integer;
var
  pos, mark, cnt: Integer;
begin
  pos := id.Processed;
  mark := id.IStart;
  cnt := 0;
  Result := PDMP3_NEED_MORE;
  while (Get_Inbuf_Filled(id) > 4) do
  begin
    Result := Read_Header(id);
    if (id.GFrameHeader.Layer = 3) then
    begin
      if (Result = PDMP3_OK) or (Result = PDMP3_NEW_FORMAT) then
        Break;
    end;
    Inc(Mark);
    if (mark = INBUF_SIZE) then
      mark := 0;
    id.IStart := mark;
    id.Processed := pos;
    Inc(cnt);
    if (cnt > (2*576)) then
    begin
      { more than one frame and still no header }
      Result := PDMP3_ERR;
      Break;
    end;
  end;
end;

{ Description: Search for next frame and read it into  buffer. Main data in
   this frame is saved for two frames since it might be needed by them.
  Parameters: Stream handle.
  Return value: PDMP3_OK if a frame is successfully read,PDMP3_ERR otherwise.
  Author: Krister Lagerström(krister@kmlager.com) }
function Read_Frame(var id: TPdmp3Handle): Integer;
begin
  Result := PDMP3_ERR;
  { Try to find the next frame in the bitstream and decode it }
  if (Search_Header(id) <> PDMP3_OK) then
    Exit;

{$ifdef ACS_DEBUG}
  Inc(Mp3Stats.FrameNum);
  WriteLn('');
  WriteLn('Frame ', Mp3Stats.FrameNum);
  dmp_fr(id.GFrameHeader);
  WriteLn('Starting decode, Layer: ', id.GFrameHeader.Layer,
          ' Rate: ', GMpeg1Bitrates[id.GFrameHeader.Layer - 1][id.GFrameHeader.BitrateIndex],
          ' Sfreq: ', GSamplingFrequency[id.GFrameHeader.SamplingFrequency]);
{$endif}
  { Get CRC word if present }
  if ((id.GFrameHeader.ProtectionBit = 0) and (Read_CRC(id) <> PDMP3_OK)) then
    Exit;

  if (id.GFrameHeader.Layer = 3) then
  begin
    { Get audio data }
    Read_Audio_L3(id);  // Get side info
    {$ifdef ACS_DEBUG}dmp_si(id.GFrameHeader, id.GSideInfo); {$endif}
    { If there's not enough main data in the bit reservoir,
      signal to calling function so that decoding isn't done! }
    { Get main data(scalefactors and Huffman coded frequency data) }
    Result := Read_Main_L3(id);
    Exit;
  end
  else
  begin
    {$ifdef ACS_DEBUG}
    WriteLn('Only layer 3(!= ', id.GFrameHeader.Layer, ') is supported!');
    {$endif}
    Exit;
  end;
  Result := PDMP3_OK;
end;

{ Description: Does inverse modified DCT and windowing.
  Parameters: AIn - array [0..17] of Real
  Author: Krister Lagerström(krister@kmlager.com) }
procedure IMDCT_Win(const AIn; var AOut: TRealArr36; block_type: Integer);
var
  i, m, N, p: Integer;
  sum: Real;
  tin: array[0..17] of Real;
begin
  for i := 0 to 35 do
    AOut[i] := 0.0;
  for i := 0 to 17 do
    tin[i] := TRealArr18(AIn)[i];

  if (block_type = 2) then
  begin
    { 3 short blocks }
    N := 12;
    for i := 0 to 2 do
    begin
      for p := 0 to N-1 do
      begin
        sum := 0.0;
        for m := 0 to (N div 2)-1 do
        begin
          {$ifdef IMDCT_NTABLES}
          sum := sum + tin[i+3*m] * cos_N12[m][p];
          {$else}
          sum := sum + tin[i+3*m] * Cos(C_PI / (2*N) * (2*p + 1 + N/2) * (2*m + 1));
          {$endif}
        end;
        AOut[6*i + p + 6] := AOut[6*i + p + 6] + sum * GImdctWin[block_type][p]; // TODO: FIXME +=?
      end;
    end;
  end
  else
  begin
    { block_type != 2 }
    N := 36;
    for p := 0 to N-1 do
    begin
      sum := 0.0;
      for m := 0 to (N div 2)-1 do
      begin
        {$ifdef IMDCT_NTABLES}
        sum := sum + TRealArr18(AIn)[m] * cos_N36[m][p];
        {$else}
        sum := sum + TRealArr18(AIn)[m] * Cos(C_PI / (2*N) * (2*p + 1 + N/2) * (2*m + 1));
        {$endif}
      end;
      AOut[p] := sum * GImdctWin[block_type][p];
    end;
  end;
end;

{ Description: requantize sample in subband that uses long blocks.
  Parameters: Stream handle,TBD
  Author: Krister Lagerström(krister@kmlager.com) }
procedure Requantize_Process_Long(var id: TPdmp3Handle; gr, ch, is_pos, sfb: Integer);
var
  tmp1, tmp2, tmp3, sf_mult, pf_x_pt: Real;
  idx: Integer;
const
  pretab: array[0..21] of Real = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0);
begin
  idx := Round(id.GMainData.ls[gr][ch][is_pos]);
  if idx = 0 then Exit;

  if id.GSideInfo.ScalefacScale[gr][ch] <> 0 then
    sf_mult := 1.0
  else
    sf_mult := 0.5;
  pf_x_pt := id.GSideInfo.Preflag[gr][ch] * pretab[sfb];
  tmp1 := Power(2.0, -(sf_mult * (id.GMainData.ScalefacL[gr][ch][sfb] + pf_x_pt)));
{$ifdef GGAIN_TABLE}
  tmp2 := GlobalGainTable[id.GSideInfo.GlobalGain[gr][ch]];
{$else}
  tmp2 := Power(2.0, 0.25 * (Integer(id.GSideInfo.GlobalGain[gr][ch]) - 210));
{$endif}
  if idx < 0 then
    tmp3 := -Requantize_Pow_43(-idx)
  else
    tmp3 := Requantize_Pow_43(idx);
  id.GMainData.ls[gr][ch][is_pos] := tmp1 * tmp2 * tmp3;
end;

{ Description: requantize sample in subband that uses short blocks.
  Author: Krister Lagerström(krister@kmlager.com) }
procedure Requantize_Process_Short(var id: TPdmp3Handle; gr, ch, is_pos, sfb, win: Integer);
var
  tmp1, tmp2, tmp3, sf_mult: Real;
  idx: Integer;
begin
  idx := Round(id.GMainData.ls[gr][ch][is_pos]);
  if idx = 0 then Exit;

  if id.GSideInfo.ScalefacScale[gr][ch] <> 0 then
    sf_mult := 1.0
  else
    sf_mult := 0.5;
  tmp1 := Power(2.0, -(sf_mult * id.GMainData.ScalefacS[gr][ch][sfb][win]));
  tmp2 := Power(2.0,  0.25 * (Integer(id.GSideInfo.GlobalGain[gr][ch]) - 210
                     - 8 * id.GSideInfo.SubblockGain[gr][ch][win]));
  if idx < 0 then
    tmp3 := -Requantize_Pow_43(-idx)
  else
    tmp3 := Requantize_Pow_43(idx);
  id.GMainData.ls[gr][ch][is_pos] := tmp1 * tmp2 * tmp3;
end;

{ Description: intensity stereo processing for entire subband with long blocks.
  Parameters: Stream handle,TBD
  Return value: TBD
  Author: Krister Lagerström(krister@kmlager.com) }
procedure Stereo_Process_Intensity_Long(var id: TPdmp3Handle; gr, sfb: Integer);
var
  i, sfreq, sfb_start, sfb_stop, is_pos: Integer;
  is_ratio_l, is_ratio_r, left, right: Real;
begin
  { Check that((is_pos[sfb]=scalefac) != 7) => no intensity stereo }
  is_pos := id.GMainData.ScalefacL[gr][0][sfb];
  if (is_pos <> 7) then
  begin
    sfreq := id.GFrameHeader.SamplingFrequency; // Setup sampling freq index
    sfb_start := GSfBandIndices[sfreq].l[sfb];
    sfb_stop := GSfBandIndices[sfreq].l[sfb+1];
    if (is_pos = 6) then
    begin
      { tan((6*PI)/12 = PI/2) needs special treatment! }
      is_ratio_l := 1.0;
      is_ratio_r := 0.0;
    end
    else
    begin
      is_ratio_l := is_ratios[is_pos] / (1.0 + is_ratios[is_pos]);
      is_ratio_r := 1.0 / (1.0 + is_ratios[is_pos]);
    end;
    { Now decode all samples in this scale factor band }
    for i := sfb_start to sfb_stop-1 do
    begin
      left  := is_ratio_l * id.GMainData.ls[gr][0][i];
      right := is_ratio_r * id.GMainData.ls[gr][0][i];
      id.GMainData.ls[gr][0][i] := left;
      id.GMainData.ls[gr][1][i] := right;
    end;
  end;
end;

{ Description: This function is used to perform intensity stereo processing
               for an entire subband that uses short blocks.
  Parameters: Stream handle,TBD
  Return value: TBD
  Author: Krister Lagerström(krister@kmlager.com) }
procedure Stereo_Process_Intensity_Short(var id: TPdmp3Handle; gr, sfb: Integer);
var
  sfb_start, sfb_stop, is_pos: Integer;
  i, sfreq, win, win_len: Integer;
  is_ratio_l, is_ratio_r, left, right: Real;
begin
  sfreq := id.GFrameHeader.SamplingFrequency;   // Setup sampling freq index
  { The window length }
  win_len := GSfBandIndices[sfreq].s[sfb+1] - GSfBandIndices[sfreq].s[sfb];
  { The three windows within the band has different scalefactors }
  for win := 0 to 2 do
  begin
    { Check that((is_pos[sfb]=scalefac) != 7) => no intensity stereo }
    is_pos := id.GMainData.ScalefacS[gr][0][sfb][win];
    if (is_pos <> 7) then
    begin
      { not illegal is_pos) }
      sfb_start := (GSfBandIndices[sfreq].s[sfb] * 3) + (win_len * win);
      sfb_stop := sfb_start + win_len;
      if is_pos = 6 then
      begin
        { tan((6*PI)/12 = PI/2) needs special treatment! }
        is_ratio_l := 1.0;
        is_ratio_r := 0.0;
      end
      else
      begin
        is_ratio_l := is_ratios[is_pos] / (1.0 + is_ratios[is_pos]);
        is_ratio_r := 1.0 / (1.0 + is_ratios[is_pos]);
      end;
      { Now decode all samples in this scale factor band }
      for i := sfb_start to sfb_stop-1 do
      begin
        is_ratio_l := id.GMainData.ls[gr][0][i];
        is_ratio_r := id.GMainData.ls[gr][0][i];
        left  := is_ratio_l;
        right := is_ratio_r;
        id.GMainData.ls[gr][0][i] := left;
        id.GMainData.ls[gr][1][i] := right;
      end;
    end;
  end;
end;

{ Author: Krister Lagerström(krister@kmlager.com) }
procedure L3_Antialias(var id: TPdmp3Handle; gr, ch: Integer);
var
  sb: Integer; // subband of 18 samples
  i, sblim, ui, li: Integer;
  ub, lb: Real;
begin
  { No antialiasing is done for short blocks }
  if ((id.GSideInfo.WinSwitchFlag[gr][ch] = 1)
  and (id.GSideInfo.BlockType[gr][ch] = 2)
  and (id.GSideInfo.MixedBlockFlag[gr][ch] = 0))
  then
    Exit;

  { Setup the limit for how many subbands to transform }
  if ((id.GSideInfo.WinSwitchFlag[gr][ch] = 1)
  and (id.GSideInfo.BlockType[gr][ch] = 2)
  and (id.GSideInfo.MixedBlockFlag[gr][ch] = 1))
  then
    sblim := 2
  else
    sblim := 32;
  { Do the actual antialiasing }
  for sb := 1 to sblim-1 do
  begin
    for i := 0 to 7 do
    begin
      li := 18 * sb - 1 - i;
      ui := 18 * sb + i;
      lb := id.GMainData.ls[gr][ch][li] * cs[i] - id.GMainData.ls[gr][ch][ui] * ca[i];
      ub := id.GMainData.ls[gr][ch][ui] * cs[i] + id.GMainData.ls[gr][ch][li] * ca[i];
      id.GMainData.ls[gr][ch][li] := lb;
      id.GMainData.ls[gr][ch][ui] := ub;
    end;
  end;
end;

{ Author: Krister Lagerström(krister@kmlager.com) }
procedure L3_Frequency_Inversion(var id: TPdmp3Handle; gr, ch: Integer);
var
  sb, i: Integer;
begin
  sb := 1;
  while sb < 32 do
  begin
    i := 1;
    while i < 18 do
    begin
      id.GMainData.ls[gr][ch][sb*18 + i] := -id.GMainData.ls[gr][ch][sb*18 + i];
      Inc(i, 2);
    end;
    Inc(sb, 2); //OPT? : for(sb = 18; sb < 576; sb += 36)
  end;
end;

{ Author: Krister Lagerström(krister@kmlager.com) }
procedure L3_Hybrid_Synthesis(var id: TPdmp3Handle; gr, ch: Integer);
var
  sb, i, j, bt: Integer;
  RawOut: TRealArr36;
begin
  if (id.HSynthInit <> 0) then
  begin
    { Clear stored samples vector. OPT? use memset }
    for j := 0 to 1 do
    begin
      for sb := 0 to 31 do
      begin
        for i := 0 to 17 do
          id.HSynthStore[j][sb][i] := 0.0;
      end;
    end;
    id.HSynthInit := 0;
  end;
  for sb := 0 to 31 do
  begin
    { Loop through all 32 subbands }
    { Determine blocktype for this subband }
    if ((id.GSideInfo.WinSwitchFlag[gr][ch] = 1)
    and (id.GSideInfo.MixedBlockFlag[gr][ch] = 1)
    and (sb < 2))
    then
      bt := 0
    else
      bt := id.GSideInfo.BlockType[gr][ch];
    { Do the inverse modified DCT and windowing }
    IMDCT_Win(id.GMainData.ls[gr][ch][sb*18], RawOut, bt);
    for i := 0 to 17 do
    begin
      { Overlapp add with stored vector into main_data vector }
      id.GMainData.ls[gr][ch][sb*18 + i] := RawOut[i] + id.HSynthStore[ch][sb][i];
      id.HSynthStore[ch][sb][i] := RawOut[i + 18];
    end;
  end;
end;

{ Author: Krister Lagerström(krister@kmlager.com) }
procedure L3_Reorder(var id: TPdmp3Handle; gr, ch: Integer);
var
  sfreq, i, j, next_sfb, sfb, win_len, win: Integer;
  re: array[0..575] of Real;
begin
  sfreq := id.GFrameHeader.SamplingFrequency; // Setup sampling freq index
  { Only reorder short blocks }
  if ((id.GSideInfo.WinSwitchFlag[gr][ch] = 1)
  and (id.GSideInfo.BlockType[gr][ch] = 2)) // Short blocks
  then
  begin
    { Check if the first two subbands
      (=2*18 samples = 8 long or 3 short sfb's) uses long blocks }
    if (id.GSideInfo.MixedBlockFlag[gr][ch] <> 0) then // 2 longbl. sb  first
    begin
      sfb := 3;
      i := 36; // Don't touch the first 36 samples
    end
    else // Only short blocks
    begin
      sfb := 0;
      i := 0;
    end;
    { Reorder the remaining, non-zero, bands which uses short blocks }
    next_sfb := GSfBandIndices[sfreq].s[sfb + 1] * 3;
    win_len := GSfBandIndices[sfreq].s[sfb + 1] - GSfBandIndices[sfreq].s[sfb];

    re[0] := 0;  // solve warning
    while i < 576 do
    begin
      { Inc(i) done below! }
      { Check if we're into the next scalefac band }
      if (i = next_sfb) then
      begin
        { Yes }
        { Copy reordered data back to the original vector }
        for j := 0 to (3 * win_len) - 1 do
          id.GMainData.ls[gr][ch][3 * GSfBandIndices[sfreq].s[sfb] + j] := re[j];
        { Check if this band is above the rzero region,if so we're done }
        if (i >= id.GSideInfo.Count1[gr][ch]) then
          Exit; // Done
        Inc(sfb);
        next_sfb := GSfBandIndices[sfreq].s[sfb + 1] * 3;
        win_len := GSfBandIndices[sfreq].s[sfb + 1] - GSfBandIndices[sfreq].s[sfb];
      end;
      for win := 0 to 2 do
      begin
        { Do the actual reordering }
        for j := 0 to win_len-1 do
        begin
          re[j*3 + win] := id.GMainData.ls[gr][ch][i];
          Inc(i);
        end;
      end;
    end;
    { Copy reordered data of last band back to original vector }
    for j := 0 to (3 * win_len) - 1 do
      id.GMainData.ls[gr][ch][3 * GSfBandIndices[sfreq].s[12] + j] := re[j];
  end;
  // else only long blocks
end;

{ Author: Krister Lagerström(krister@kmlager.com) }
procedure L3_Requantize(var id: TPdmp3Handle; gr, ch: Integer);
var
  sfb: Integer; // scalefac band index
  next_sfb: Integer; // frequency of next sfb
  sfreq, i, j, win, win_len: Integer;
begin
  { Setup sampling frequency index }
  sfreq := id.GFrameHeader.SamplingFrequency;
  { Determine type of block to process }
  if ((id.GSideInfo.WinSwitchFlag[gr][ch] = 1)
  and (id.GSideInfo.BlockType[gr][ch] = 2)) // Short blocks
  then
  begin
    { Check if the first two subbands
      (=2*18 samples = 8 long or 3 short sfb's) uses long blocks }
    if (id.GSideInfo.MixedBlockFlag[gr][ch] <> 0) then
    begin
      { 2 longbl. sb  first }
      { First process the 2 long block subbands at the start }
      sfb := 0;
      next_sfb := GSfBandIndices[sfreq].l[sfb + 1];
      for i := 0 to 35 do
      begin
        if (i = next_sfb) then
        begin
          Inc(sfb);
          next_sfb := GSfBandIndices[sfreq].l[sfb + 1];
        end;
        Requantize_Process_Long(id, gr, ch, i, sfb);
      end;
      { And next the remaining, non-zero, bands which uses short blocks }
      sfb := 3;
      next_sfb := GSfBandIndices[sfreq].s[sfb + 1] * 3;
      win_len := GSfBandIndices[sfreq].s[sfb + 1] - GSfBandIndices[sfreq].s[sfb];

      i := 36;
      while i < id.GSideInfo.Count1[gr][ch] do
      begin
        { Inc(i) done below! }
        { Check if we're into the next scalefac band }
        if i = next_sfb then
        begin
          { Yes }
          Inc(sfb);
          next_sfb := GSfBandIndices[sfreq].s[sfb + 1] * 3;
          win_len := GSfBandIndices[sfreq].s[sfb + 1] - GSfBandIndices[sfreq].s[sfb];
        end;
        for win := 0 to 2 do
        begin
          for j := 0 to win_len-1 do
          begin
            Requantize_Process_Short(id, gr, ch, i, sfb, win);
            Inc(i);
          end;
        end;
      end;
    end
    else
    begin
      { Only short blocks }
      sfb := 0;
      next_sfb := GSfBandIndices[sfreq].s[sfb + 1] * 3;
      win_len := GSfBandIndices[sfreq].s[sfb + 1] - GSfBandIndices[sfreq].s[sfb];
      i := 0;
      while i < id.GSideInfo.Count1[gr][ch] do
      begin
        { Inc(i) done below! }
        { Check if we're into the next scalefac band }
        if i = next_sfb then
        begin
          { Yes }
          Inc(sfb);
          next_sfb := GSfBandIndices[sfreq].s[sfb + 1] * 3;
          win_len := GSfBandIndices[sfreq].s[sfb + 1] - GSfBandIndices[sfreq].s[sfb];
        end;
        Assert(sfb < 13);
        for win := 0 to 2 do
        begin
          for j := 0 to win_len-1 do
          begin
            Requantize_Process_Short(id, gr, ch, i, sfb, win);
            Inc(i);
          end;
        end;
      end;
    end; // end else(only short blocks)
  end
  else
  begin
    { Only long blocks }
    sfb := 0;
    next_sfb := GSfBandIndices[sfreq].l[sfb + 1];
    for i := 0 to id.GSideInfo.count1[gr][ch] - 1 do
    begin
      if i = next_sfb then
      begin
        Inc(sfb);
        next_sfb := GSfBandIndices[sfreq].l[sfb + 1];
      end;
      Requantize_Process_Long(id, gr, ch, i, sfb);
    end;
  end;
end;

{ Author: Krister Lagerström(krister@kmlager.com) }
procedure L3_Stereo(var id: TPdmp3Handle; gr: integer);
var
  max_pos, i , sfreq: Integer;
  sfb: Integer; // scalefac band index
  left, right: Real;
begin
  { Do nothing if joint stereo is not enabled }
  if ((id.GFrameHeader.Mode <> 1) or (id.GFrameHeader.ModeExtension = 0)) then
    Exit;

  { Do Middle/Side("normal") stereo processing }
  if (id.GFrameHeader.ModeExtension and $02) <> 0 then  // ms_stereo
  begin
    { Determine how many frequency lines to transform }
    if (id.GSideInfo.Count1[gr][0] > id.GSideInfo.Count1[gr][1]) then
      max_pos := id.GSideInfo.Count1[gr][0]
    else
      max_pos := id.GSideInfo.Count1[gr][1];
    { Do the actual processing }
    for i := 0 to max_pos-1 do
    begin
      left  := (id.GMainData.ls[gr][0][i] + id.GMainData.ls[gr][1][i]) * C_INV_SQRT_2;
      right := (id.GMainData.ls[gr][0][i] - id.GMainData.ls[gr][1][i]) * C_INV_SQRT_2;
      id.GMainData.ls[gr][0][i] := left;
      id.GMainData.ls[gr][1][i] := right;
    end;
  end;

  { Do intensity stereo processing }
  if (id.GFrameHeader.ModeExtension and $01) <> 0 then  // intensity_stereo
  begin
    { Setup sampling frequency index }
    sfreq := id.GFrameHeader.SamplingFrequency;
    { First band that is intensity stereo encoded is first band scale factor
      band on or above count1 frequency line. N.B.: Intensity stereo coding is
      only done for higher subbands, but logic is here for lower subbands. }
    { Determine type of block to process }
    if ((id.GSideInfo.WinSwitchFlag[gr][0] = 1)
    and (id.GSideInfo.BlockType[gr][0] = 2)) // Short blocks
    then
    begin
      { Check if the first two subbands
        (=2*18 samples = 8 long or 3 short sfb's) uses long blocks }
      if (id.GSideInfo.MixedBlockFlag[gr][0] <> 0) then
      begin
        { 2 longbl. sb  first }
        for sfb := 0 to 7 do
        begin
          { First process 8 sfb's at start }
          { Is this scale factor band above count1 for the right channel? }
          if GSfBandIndices[sfreq].l[sfb] >= id.GSideInfo.Count1[gr][1] then
            Stereo_Process_Intensity_Long(id, gr, sfb);
        end;
        { And next the remaining bands which uses short blocks }
        for sfb := 3 to 11 do
        begin
          { Is this scale factor band above count1 for the right channel? }
          if GSfBandIndices[sfreq].s[sfb]*3 >= id.GSideInfo.Count1[gr][1] then
            Stereo_Process_Intensity_Short(id, gr, sfb); // intensity stereo processing
        end;
      end
      else
      begin
        { Only short blocks }
        for sfb := 0 to 11 do
        begin
          { Is this scale factor band above count1 for the right channel? }
          if GSfBandIndices[sfreq].s[sfb]*3 >= id.GSideInfo.Count1[gr][1] then
            Stereo_Process_Intensity_Short(id, gr, sfb); // intensity stereo processing
        end;
      end;
    end
    else
    begin
      { Only long blocks }
      for sfb := 0 to 20 do
      begin
        { Is this scale factor band above count1 for the right channel? }
        if GSfBandIndices[sfreq].l[sfb] >= id.GSideInfo.Count1[gr][1] then
        begin
          { Perform the intensity stereo processing }
          Stereo_Process_Intensity_Long(id, gr, sfb);
        end;
      end;
    end;
  end;
end;

{ Description: Polyphase subband synthesis
  Parameters: Stream handle,TBD
  Return value: TBD
  Author: Krister Lagerström(krister@kmlager.com) }
procedure L3_Subband_Synthesis(var id: TPdmp3Handle; gr, ch: Integer; var outdata: TLongWordArr576);
var
  u_vec: array[0..511] of Real;
  s_vec: array[0..31] of Real; // u_vec can be used insted of s_vec
  sum: Real;
  samp: LongInt;
  //static unsigned init = 1;
  i, j, ss, nch: Integer;
  //static float g_synth_n_win[64][32],v_vec[2 /* ch */][1024];
begin
  { Number of channels(1 for mono and 2 for stereo) }
  nch := GetChanCount(id);

  if (id.SynthInit <> 0) then
  begin
    { Setup the v_vec intermediate vector }
    for i := 0 to 1 do
    begin
      for j := 0 to 1023 do
        id.v_vec[i][j] := 0.0; { TODO: memset }
    end;
    id.SynthInit := 0;
  end;

  { Loop through 18 samples in 32 subbands }
  for ss := 0 to 17 do
  begin
    { Shift up the V vector }
    for i := 1023 downto 64 do
    begin
      id.v_vec[ch][i] := id.v_vec[ch][i-64];
    end;
    { Copy next 32 time samples to a temp vector }
    for i := 0 to 31 do
    begin
      s_vec[i] := id.GMainData.ls[gr][ch][i*18 + ss];
    end;
    { Matrix multiply input with n_win[][] matrix }
    for i := 0 to 63 do
    begin
      sum := 0.0;
      for j := 0 to 31 do
        sum := sum + GSynthNWin[i][j] * s_vec[j];
      id.v_vec[ch][i] := sum;
    end;
    { Build the U vector }
    for i := 0 to 7 do
    begin
      for j := 0 to 31 do
      begin
        { <<7 == *128 }
        u_vec[(i shl 6) + j]      := id.v_vec[ch][(i shl 7) + j];
        u_vec[(i shl 6) + j + 32] := id.v_vec[ch][(i shl 7) + j + 96];
      end;
    end;
    { Window by u_vec[i] with GSynthDtbl[i] }
    for i := 0 to 511 do
    begin
      u_vec[i] := u_vec[i] * GSynthDtbl[i];
    end;
    { Calc 32 samples, store in outdata vector }
    for i := 0 to 31 do
    begin
      sum := 0.0;
      for j := 0 to 15 do // sum += u_vec[j*32 + i];
        sum := sum + u_vec[(j shl 5) + i];
      { sum now contains time sample 32 * ss + i. Convert to 16-bit signed int }
      samp := LongInt(Round(sum * 32767.0));
      if (samp > 32767) then
        samp := 32767
      else if (samp < -32767) then
        samp := -32767;
      samp := samp and $ffff;
      if ch = 0 then
      begin
        { This function must be called for channel 0 first }
        { We always run in stereo mode, duplicate channels here for mono }
        if nch = 1 then
          outdata[32*ss + i] := (Cardinal(samp) shl 16) or samp
        else
          outdata[32*ss + i] := Cardinal(samp) shl 16;
      end
      else
      begin
        outdata[32*ss + i] := outdata[32*ss + i] or samp;
      end;
    end;
  end;
end;

{ Description: decodes a layer 3 bitstream into audio samples.
  Parameters: Stream handle,outdata vector.
  Return value: PDMP3_OK or PDMP3_ERR if the frame contains errors.
  Author: Krister Lagerström(krister@kmlager.com) }
function Decode_L3(var id: TPdmp3Handle): Integer;
var
  gr, ch, nch: Integer;
  i, ctr: Integer;
begin
  // Number of channels(1 for mono and 2 for stereo)
  nch := GetChanCount(id);

  for gr := 0 to 1 do
  begin
    for ch := 0 to nch-1 do
    begin
      {$ifdef ACS_DEBUG}dmp_scf(id.GSideInfo, id.GMainData, gr, ch); {$endif}
      {$ifdef ACS_DEBUG}dmp_huff(id.GMainData, gr, ch); {$endif}
      L3_Requantize(id, gr, ch); // Requantize samples
      {$ifdef ACS_DEBUG}dmp_samples(id.GMainData, gr, ch, 0); {$endif}
      L3_Reorder(id, gr, ch); // Reorder short blocks
    end;
    L3_Stereo(id, gr); // Stereo processing
    {$ifdef ACS_DEBUG}dmp_samples(id.GMainData, gr, 0, 1); {$endif}
    {$ifdef ACS_DEBUG}dmp_samples(id.GMainData, gr, 1, 1); {$endif}
    for ch := 0 to nch-1 do
    begin
      L3_Antialias(id, gr, ch); // Antialias
      {$ifdef ACS_DEBUG}dmp_samples(id.GMainData, gr, ch, 2); {$endif}
      L3_Hybrid_Synthesis(id, gr, ch); // (IMDCT,windowing,overlapp add)
      L3_Frequency_Inversion(id, gr, ch); // Frequency inversion
      {$ifdef ACS_DEBUG}dmp_samples(id.GMainData, gr, ch, 3); {$endif}
      L3_Subband_Synthesis(id, gr, ch, id._out[gr]); // Polyphase subband synthesis
    end;
    {$ifdef ACS_DEBUG}
    ctr := 0;
    WriteLn('PCM:');
    for i := 0 to 575 do
    begin
      Inc(ctr);
      WriteLn(ctr, ': ', ((id._out[gr][i] shr 16) and $ffff));
      if (nch = 2) then
      begin
        Inc(ctr);
        WriteLn(ctr, ': ', (id._out[gr][i] and $ffff));
      end;
    end;
    {$endif DEBUG}
  end;
  Result := PDMP3_OK;   // Done
end;

{#############################################################################
  Stream API - Added for AeonWave Audio (http://www.adalin.com)
  This is a subset of the libmpg123 API and should by 100% compatible.

  Au0thor: Erik Hofman(erik@ehofman.com) }
procedure Convert_Frame_S16(var id: TPdmp3Handle; var outbuf; buflen: Integer; out done: Integer);
type
  TSmallIntArr2x576 = array[0..4*576-1] of SmallInt; // 16 bit integer, buffer is twice larger for 2-channel output
var
  ps: ^TSmallIntArr2x576;
  lo, hi, nsamps, framesz: Integer;
  q, i, nch, gr: Integer;
begin
  nch := GetChanCount(id);
  framesz := SizeOf(SmallInt) * nch;
  ps := Addr(outbuf);

  nsamps := buflen div framesz;
  if (nsamps > (2*576 - id.OStart)) then
    nsamps := 2*576 - id.OStart;
  done := nsamps * framesz;

  i := id.OStart mod 576;
  gr := id.OStart div 576;
  for q := 0 to nsamps-1 do
  begin
    if nch = 1 then
    begin
      lo := id._out[gr][i] and $ffff;
      ps^[q] := SmallInt(lo);
    end
    else
    begin
      lo :=  id._out[gr][i] and $ffff;
      hi := (id._out[gr][i] and $ffff0000) shr 16;
      ps^[2*q] := SmallInt(hi);
      ps^[2*q+1] := SmallInt(lo);
    end;
    Inc(i);
    if i = 576 then
    begin
       Inc(gr);
       i := 0;
    end;
  end;

  { copy to outbuf }
  Inc(id.OStart, nsamps);
  if (id.OStart = (2*576)) then
    id.OStart := 0;
end;

{ Description: Resets the stream handle.
  Parameters: Stream handle
  Return value: PDMP3_OK or PDMP3_ERR
  Author: Erik Hofman(erik@ehofman.com) }
function pdmp3_open_feed(var id: TPdmp3Handle): Integer;
begin
  id.OStart := 0;
  id.IStart := 0;
  id.IEnd := 0;
  id.Processed := 0;
  id.NewHeader := 0;

  id.HSynthInit := 1;
  id.SynthInit := 1;
  id.GMainDataTop := 0;

  Result := PDMP3_OK;
end;

{ Description: Feed new data to the MP3 decoder
  Parameters: Streaming handle,data buffer containging MP3 data, size fo the
              data buffer.
  Return value: PDMP3_OK or an error
  Author: Erik Hofman(erik@ehofman.com) }
function pdmp3_feed(var id: TPdmp3Handle; const AIn; ASize: Integer): Integer;
var
  free, res: Integer;
  p: PByte;
begin
  if ASize > 0 then
  begin
    free := Get_Inbuf_Free(id);
    if ASize <= free then
    begin
      if (id.IEnd < id.IStart) then
      begin
        res := id.IStart - id.IEnd;
        if (ASize < res) then
          res := ASize;
        Move(AIn, id._in[id.IEnd], res);
        Inc(id.IEnd, res);
      end
      else
      begin
        res := INBUF_SIZE - id.IEnd;
        if (ASize < res) then
          res := ASize;
        if (res > 0) then
        begin
          Move(AIn, id._in[id.IEnd], res);
          Inc(id.IEnd, res);
          Dec(ASize, res);
        end;
        if (ASize > 0) then
        begin
          { pointer arithmetic }
          p := Addr(AIn);
          Inc(p, res);
          Move(p^, id._in, ASize);
          id.IEnd := ASize;
        end;
      end;
      Result := PDMP3_OK;
    end
    else
      Result := PDMP3_NO_SPACE;
  end
  else
    Result := PDMP3_ERR;
end;

{ Description: Convert MP3 data to PCM data
  Parameters: Stream handle,a pointer to a buffer for the PCM data,the size of
              the PCM buffer in bytes,a pointer to return the number of
              converted bytes.
  Return value: PDMP3_OK or an error.
  Author: Erik Hofman(erik@ehofman.com) }
function pdmp3_read(var id: TPdmp3Handle; var outmemory; outsize: Integer; out done: Integer): Integer;
var
  pos, mark, batch: Integer;
  pOutBuf: PByte;
begin
  if (outsize > 0) then
  begin
    done := 0;
    if (outsize > 0) then
    begin
      Result := PDMP3_ERR;
      pOutBuf := Addr(outmemory);
      if (id.OStart > 0) then
      begin
        Convert_Frame_S16(id, pOutBuf^, outsize, done);
        Inc(pOutBuf, done);
        Dec(outsize, done);
        Result := PDMP3_OK;
      end;

      while (outsize > 0) do
      begin
        if (Get_Inbuf_Filled(id) >= (2*576)) then
        begin
          pos := id.Processed;
          mark := id.IStart;

          Result := Read_Frame(id);
          if (Result = PDMP3_OK) or (Result = PDMP3_NEW_FORMAT) then
          begin
            Decode_L3(id);
            Convert_Frame_S16(id, pOutBuf^, outsize, batch);
            Inc(pOutBuf, batch);
            Dec(outsize, batch);
            Inc(done, batch);
          end
          else
          begin
            id.Processed := pos;
            id.IStart := mark;
            Break;
          end;
        end
        else
        begin
          Result := PDMP3_NEED_MORE;
          Break;
        end;
      end;

      if (id.NewHeader = 1) and (Result = PDMP3_OK) then
        Result := PDMP3_NEW_FORMAT;
      Exit;
    end
    else if (outsize < (2*576)) then
      Result := PDMP3_NO_SPACE
    else
      Result := PDMP3_NEED_MORE;
  end
  else
    Result := PDMP3_ERR;
end;

{ Description: Feed new data to the MP3 decoder and optionally convert it
               to PCM data.
  Parameters: Stream handle,a pinter to the MP3 data,size of the MP3 buffer,
              a pointer to a buffer for the PCM data or NULL,the size of
              the PCM buffer in bytes,a pointer to return the number of
  d->ostart            converted bytes.
  Return value: PDMP3_OK or an error.
  Author: Erik Hofman(erik@ehofman.com) }
function pdmp3_decode(var id: TPdmp3Handle; const AIn; AInSize: Integer;
  var AOut; AOutSize: Integer; out ADone: Integer): Integer;
var
  free, avail, pos, mark: Integer;
begin
  free := Get_Inbuf_Free(id);
  ADone := 0;
  if (free > AInSize) then
    free := AInSize;
  Result := pdmp3_feed(id, AIn, free);

  if (Result = PDMP3_OK) then
  begin
    if (AOutSize > 0) then
    begin
      Result := pdmp3_read(id, AOut, AOutSize, avail);
      ADone := avail;
    end
    else if (Get_Filepos(id) = 0) then
    begin
      pos := id.Processed;
      mark := id.IStart;
      Result := Search_Header(id);
      id.Processed := pos;
      id.IStart := mark;

      if (id.NewHeader = 1) then
        Result := PDMP3_NEW_FORMAT;

    end;
  end;
end;

{ Description: Get the current output format written to the addresses given.
  Parameters: Stream handle,pointers to store rate, channels and encoding.
  Return value: PDMP3_OK or an error
  Author: Erik Hofman(erik@ehofman.com) }
function pdmp3_getformat(var id: TPdmp3Handle; out rate, channels, encoding: Integer): Integer;
begin
  encoding := PDMP3_ENC_SIGNED_16;
  rate := GSamplingFrequency[id.GFrameHeader.SamplingFrequency];
  channels := GetChanCount(id);
  id.NewHeader := -1;
  Result := PDMP3_OK;
end;


initialization

{$ifdef POW34_TABLE}
InitPowtab43();
{$endif}

{$ifdef IMDCT_TABLE}
InitImdct();
{$endif}

{$ifdef GGAIN_TABLE}
InitGlobalGainTable();
{$endif}

InitSynthNWin();

end.
